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+ //! # Example
7+ //!
8+ //! ```rust
9+ //! use embed_collections::irc::{Irc, IrcItem};
10+ //! use core::sync::atomic::{AtomicUsize, AtomicBool, Ordering};
11+ //! use crossfire::oneshot;
12+ //! use std::thread;
13+ //! use std::time::Duration;
14+ //!
15+ //! struct MyItem {
16+ //! is_done: AtomicBool,
17+ //! counter: AtomicUsize,
18+ //! done_tx: Option<oneshot::TxOneshot<Box<MyItem>>>,
19+ //! }
20+ //!
21+ //! unsafe impl IrcItem<()> for MyItem {
22+ //! type Counter = AtomicUsize;
23+ //! fn counter(&self) -> &Self::Counter {
24+ //! &self.counter
25+ //! }
26+ //!
27+ //! // overwrite default behavior to send the item through channel
28+ //! fn on_drop(mut this: Box<Self>) {
29+ //! let done_tx = this.done_tx.take().unwrap();
30+ //! done_tx.send(this);
31+ //! }
32+ //! }
33+ //!
34+ //! let (done_tx, done_rx) = oneshot::oneshot();
35+ //! let boxed_item = Box::new(MyItem {
36+ //! is_done: AtomicBool::new(false),
37+ //! counter: AtomicUsize::new(0),
38+ //! done_tx: Some(done_tx),
39+ //! });
40+ //!
41+ //! // Convert from Box to Irc, which does not have additional allocation.
42+ //! let item = Irc::<_, ()>::from(boxed_item);
43+ //! thread::spawn(move || {
44+ //! thread::sleep(Duration::from_secs(1));
45+ //! item.is_done.store(true, Ordering::SeqCst);
46+ //! drop(item);
47+ //! });
48+ //! let item: Box<MyItem> = done_rx.recv().unwrap();
49+ //! assert!(item.is_done.load(Ordering::SeqCst));
50+ //! ```
51+
152use crate :: { Pointer , SmartPointer } ;
253use atomic_traits:: {
354 Atomic , NumOps ,
@@ -78,6 +129,37 @@ impl<T: IrcItem<Tag>, Tag> Irc<T, Tag> {
78129 ///
79130 /// it's possible to return false when counter drop to 1,
80131 /// Because of using Acquire load and Release on drop.
132+ ///
133+ /// # Example
134+ ///
135+ ///
136+ /// ```rust
137+ /// use embed_collections::irc::{Irc, IrcItem};
138+ /// use core::sync::atomic::AtomicUsize;
139+ ///
140+ /// struct Tag;
141+ ///
142+ /// struct MyItem {
143+ /// value: i32,
144+ /// counter: AtomicUsize,
145+ /// }
146+ ///
147+ /// unsafe impl IrcItem<Tag> for MyItem {
148+ /// type Counter = AtomicUsize;
149+ /// fn counter(&self) -> &Self::Counter {
150+ /// &self.counter
151+ /// }
152+ /// }
153+ ///
154+ /// // Create a new Irc
155+ /// let irc1 = Irc::<_, Tag>::new(MyItem { value: 10, counter: AtomicUsize::new(0) });
156+ /// assert_eq!(irc1.value, 10);
157+ /// assert!(irc1.is_unique());
158+ ///
159+ /// // Clone the Irc
160+ /// let irc2 = irc1.clone();
161+ /// assert_eq!(irc1.strong_count(), 2);
162+ /// assert!(!irc1.is_unique());
81163 #[ inline]
82164 pub fn is_unique ( & self ) -> bool {
83165 // Safety:
@@ -99,6 +181,42 @@ impl<T: IrcItem<Tag>, Tag> Irc<T, Tag> {
99181
100182impl < T : IrcItem < Tag > + Clone , Tag > Irc < T , Tag > {
101183 /// The Cow function, the same as `Arc::make_mut()`
184+ ///
185+ /// # Example
186+ ///
187+ /// ```rust
188+ /// use embed_collections::irc::{Irc, IrcItem};
189+ /// use core::sync::atomic::AtomicUsize;
190+ ///
191+ /// struct Tag;
192+ /// struct MyItem {
193+ /// value: i32,
194+ /// counter: AtomicUsize,
195+ /// }
196+ ///
197+ /// impl Clone for MyItem {
198+ /// fn clone(&self) -> Self {
199+ /// Self { value: self.value, counter: AtomicUsize::new(0) }
200+ /// }
201+ /// }
202+ ///
203+ /// unsafe impl IrcItem<Tag> for MyItem {
204+ /// type Counter = AtomicUsize;
205+ /// fn counter(&self) -> &Self::Counter {
206+ /// &self.counter
207+ /// }
208+ /// }
209+ ///
210+ /// let mut irc1 = Irc::<_, Tag>::new(MyItem { value: 10, counter: AtomicUsize::new(0) });
211+ /// let irc2 = irc1.clone();
212+ ///
213+ /// // This will clone the inner item because it's shared
214+ /// let m = Irc::make_mut(&mut irc1);
215+ /// m.value = 20;
216+ ///
217+ /// assert_eq!(irc1.value, 20);
218+ /// assert_eq!(irc2.value, 10);
219+ /// ```
102220 #[ inline]
103221 pub fn make_mut ( this : & mut Self ) -> & mut T {
104222 if !this. is_unique ( ) {
@@ -211,3 +329,166 @@ impl<T: IrcItem<Tag>, Tag> SmartPointer for Irc<T, Tag> {
211329 Irc :: new ( inner)
212330 }
213331}
332+
333+ #[ cfg( test) ]
334+ mod tests {
335+ use super :: * ;
336+ use crate :: test:: { CounterI32 , alive_count, reset_alive_count} ;
337+ use core:: sync:: atomic:: AtomicUsize ;
338+ use std:: thread;
339+
340+ struct Tag ;
341+
342+ struct TestItem {
343+ value : CounterI32 ,
344+ counter : AtomicUsize ,
345+ }
346+
347+ impl TestItem {
348+ fn new ( val : i32 ) -> Self {
349+ Self { value : CounterI32 :: new ( val) , counter : AtomicUsize :: new ( 0 ) }
350+ }
351+ }
352+
353+ impl Clone for TestItem {
354+ fn clone ( & self ) -> Self {
355+ Self { value : self . value . clone ( ) , counter : AtomicUsize :: new ( 0 ) }
356+ }
357+ }
358+
359+ unsafe impl IrcItem < Tag > for TestItem {
360+ type Counter = AtomicUsize ;
361+ fn counter ( & self ) -> & Self :: Counter {
362+ & self . counter
363+ }
364+ }
365+
366+ #[ test]
367+ fn test_basic ( ) {
368+ reset_alive_count ( ) ;
369+ {
370+ let item = TestItem :: new ( 10 ) ;
371+ let irc1 = Irc :: < _ , Tag > :: new ( item) ;
372+ assert_eq ! ( irc1. value. value, 10 ) ;
373+ assert_eq ! ( irc1. strong_count( ) , 1 ) ;
374+ assert ! ( irc1. is_unique( ) ) ;
375+ assert_eq ! ( alive_count( ) , 1 ) ;
376+
377+ let irc2 = irc1. clone ( ) ;
378+ assert_eq ! ( irc1. strong_count( ) , 2 ) ;
379+ assert_eq ! ( irc2. strong_count( ) , 2 ) ;
380+ assert ! ( !irc1. is_unique( ) ) ;
381+ assert_eq ! ( alive_count( ) , 1 ) ;
382+
383+ drop ( irc1) ;
384+ assert_eq ! ( irc2. strong_count( ) , 1 ) ;
385+ assert ! ( irc2. is_unique( ) ) ;
386+ assert_eq ! ( alive_count( ) , 1 ) ;
387+ }
388+ assert_eq ! ( alive_count( ) , 0 ) ;
389+ }
390+
391+ #[ test]
392+ fn test_get_mut ( ) {
393+ reset_alive_count ( ) ;
394+ let mut irc = Irc :: < _ , Tag > :: new ( TestItem :: new ( 10 ) ) ;
395+ assert ! ( Irc :: get_mut( & mut irc) . is_some( ) ) ;
396+
397+ let _irc2 = irc. clone ( ) ;
398+ assert ! ( Irc :: get_mut( & mut irc) . is_none( ) ) ;
399+ }
400+
401+ #[ test]
402+ fn test_make_mut ( ) {
403+ reset_alive_count ( ) ;
404+ let mut irc = Irc :: < _ , Tag > :: new ( TestItem :: new ( 10 ) ) ;
405+
406+ // Unique, no clone
407+ {
408+ let m = Irc :: make_mut ( & mut irc) ;
409+ m. value . value = 20 ;
410+ }
411+ assert_eq ! ( irc. value. value, 20 ) ;
412+ assert_eq ! ( alive_count( ) , 1 ) ;
413+
414+ // Not unique, should clone
415+ let irc2 = irc. clone ( ) ;
416+ assert_eq ! ( alive_count( ) , 1 ) ;
417+ {
418+ let m = Irc :: make_mut ( & mut irc) ;
419+ m. value . value = 30 ;
420+ }
421+ assert_eq ! ( irc. value. value, 30 ) ;
422+ assert_eq ! ( irc2. value. value, 20 ) ;
423+ assert_eq ! ( alive_count( ) , 2 ) ;
424+
425+ assert ! ( irc. is_unique( ) ) ;
426+ assert ! ( irc2. is_unique( ) ) ;
427+ }
428+
429+ #[ test]
430+ fn test_multithread_count ( ) {
431+ reset_alive_count ( ) ;
432+ {
433+ let irc = Irc :: < _ , Tag > :: new ( TestItem :: new ( 0 ) ) ;
434+ let mut handles = vec ! [ ] ;
435+
436+ for _ in 0 ..10 {
437+ let irc_clone = irc. clone ( ) ;
438+ handles. push ( thread:: spawn ( move || {
439+ for _ in 0 ..1000 {
440+ let temp = irc_clone. clone ( ) ;
441+ assert_eq ! ( temp. value. value, 0 ) ;
442+ }
443+ } ) ) ;
444+ }
445+
446+ for handle in handles {
447+ handle. join ( ) . unwrap ( ) ;
448+ }
449+
450+ assert_eq ! ( irc. strong_count( ) , 1 ) ;
451+ assert ! ( irc. is_unique( ) ) ;
452+ assert_eq ! ( alive_count( ) , 1 ) ;
453+ }
454+ assert_eq ! ( alive_count( ) , 0 ) ;
455+ }
456+
457+ #[ test]
458+ fn test_multithread_drop ( ) {
459+ reset_alive_count ( ) ;
460+ {
461+ let irc = Irc :: < _ , Tag > :: new ( TestItem :: new ( 0 ) ) ;
462+ let mut handles = vec ! [ ] ;
463+ for _ in 0 ..10 {
464+ let irc_clone = irc. clone ( ) ;
465+ handles. push ( thread:: spawn ( move || {
466+ for _ in 0 ..1000 {
467+ let temp = irc_clone. clone ( ) ;
468+ assert_eq ! ( temp. value. value, 0 ) ;
469+ }
470+ } ) ) ;
471+ }
472+ drop ( irc) ;
473+ for handle in handles {
474+ handle. join ( ) . unwrap ( ) ;
475+ }
476+ }
477+ assert_eq ! ( alive_count( ) , 0 ) ;
478+ }
479+
480+ #[ test]
481+ fn test_drop_all ( ) {
482+ reset_alive_count ( ) ;
483+ let irc = Irc :: < _ , Tag > :: new ( TestItem :: new ( 0 ) ) ;
484+ let mut clones = vec ! [ ] ;
485+ for _ in 0 ..100 {
486+ clones. push ( irc. clone ( ) ) ;
487+ }
488+ assert_eq ! ( alive_count( ) , 1 ) ;
489+ drop ( clones) ;
490+ assert_eq ! ( alive_count( ) , 1 ) ;
491+ drop ( irc) ;
492+ assert_eq ! ( alive_count( ) , 0 ) ;
493+ }
494+ }
0 commit comments