@@ -134,24 +134,58 @@ use crate::stdlib::{
134
134
fmt,
135
135
sync:: {
136
136
atomic:: { AtomicBool , AtomicUsize , Ordering } ,
137
- Arc ,
137
+ Arc , Weak ,
138
138
} ,
139
139
} ;
140
140
141
141
#[ cfg( feature = "std" ) ]
142
142
use crate :: stdlib:: {
143
143
cell:: { Cell , RefCell , RefMut } ,
144
144
error,
145
- sync:: Weak ,
146
145
} ;
147
146
147
+ #[ cfg( feature = "alloc" ) ]
148
+ use alloc:: sync:: { Arc , Weak } ;
149
+
150
+ #[ cfg( feature = "alloc" ) ]
151
+ use core:: ops:: Deref ;
152
+
148
153
/// `Dispatch` trace data to a [`Subscriber`].
149
- ///
150
154
#[ derive( Clone ) ]
151
155
pub struct Dispatch {
152
156
subscriber : Arc < dyn Subscriber + Send + Sync > ,
153
157
}
154
158
159
+ /// `WeakDispatch` is a version of [`Dispatch`] that holds a non-owning reference
160
+ /// to a [`Subscriber`].
161
+ ///
162
+ /// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`],
163
+ /// which returns an `Option<Dispatch>`. If all [`Dispatch`] clones that point
164
+ /// at the `Subscriber` have been dropped, [`WeakDispatch::upgrade`] will return
165
+ /// `None`. Otherwise, it will return `Some(Dispatch)`.
166
+ ///
167
+ /// A `WeakDispatch` may be created from a [`Dispatch`] by calling the
168
+ /// [`Dispatch::downgrade`] method. The primary use for creating a
169
+ /// [`WeakDispatch`] is to allow a Subscriber` to hold a cyclical reference to
170
+ /// itself without creating a memory leak. See [here] for details.
171
+ ///
172
+ /// This type is analogous to the [`std::sync::Weak`] type, but for a
173
+ /// [`Dispatch`] rather than an [`Arc`].
174
+ ///
175
+ /// [`Arc`]: std::sync::Arc
176
+ /// [here]: Subscriber#avoiding-memory-leaks
177
+ #[ derive( Clone ) ]
178
+ pub struct WeakDispatch {
179
+ subscriber : Weak < dyn Subscriber + Send + Sync > ,
180
+ }
181
+
182
+ #[ cfg( feature = "alloc" ) ]
183
+ #[ derive( Clone ) ]
184
+ enum Kind < T > {
185
+ Global ( & ' static ( dyn Collect + Send + Sync ) ) ,
186
+ Scoped ( T ) ,
187
+ }
188
+
155
189
#[ cfg( feature = "std" ) ]
156
190
thread_local ! {
157
191
static CURRENT_STATE : State = State {
@@ -430,12 +464,23 @@ impl Dispatch {
430
464
Registrar ( Arc :: downgrade ( & self . subscriber ) )
431
465
}
432
466
433
- #[ inline( always) ]
434
- #[ cfg( feature = "alloc" ) ]
435
- pub ( crate ) fn subscriber ( & self ) -> & ( dyn Subscriber + Send + Sync ) {
436
- match self . subscriber {
437
- Kind :: Scoped ( ref s) => Arc :: deref ( s) ,
438
- Kind :: Global ( s) => s,
467
+ /// Creates a [`WeakDispatch`] from this `Dispatch`.
468
+ ///
469
+ /// A [`WeakDispatch`] is similar to a [`Dispatch`], but it does not prevent
470
+ /// the underlying [`Subscriber`] from being dropped. Instead, it only permits
471
+ /// access while other references to the `Subscriber` exist. This is equivalent
472
+ /// to the standard library's [`Arc::downgrade`] method, but for `Dispatch`
473
+ /// rather than `Arc`.
474
+ ///
475
+ /// The primary use for creating a [`WeakDispatch`] is to allow a `Subscriber`
476
+ /// to hold a cyclical reference to itself without creating a memory leak.
477
+ /// See [here] for details.
478
+ ///
479
+ /// [`Arc::downgrade`]: std::sync::Arc::downgrade
480
+ /// [here]: Subscriber#avoiding-memory-leaks
481
+ pub fn downgrade ( & self ) -> WeakDispatch {
482
+ WeakDispatch {
483
+ subscriber : Arc :: downgrade ( & self . subscriber ) ,
439
484
}
440
485
}
441
486
@@ -682,6 +727,45 @@ where
682
727
}
683
728
}
684
729
730
+ // === impl WeakDispatch ===
731
+
732
+ impl WeakDispatch {
733
+ /// Attempts to upgrade this `WeakDispatch` to a [`Dispatch`].
734
+ ///
735
+ /// Returns `None` if the referenced `Dispatch` has already been dropped.
736
+ ///
737
+ /// ## Examples
738
+ ///
739
+ /// ```
740
+ /// # use tracing_core::subscriber::NoSubscriber;
741
+ /// # use tracing_core::dispatcher::Dispatch;
742
+ /// let strong = Dispatch::new(NoSubscriber::default());
743
+ /// let weak = strong.downgrade();
744
+ ///
745
+ /// // The strong here keeps it alive, so we can still access the object.
746
+ /// assert!(weak.upgrade().is_some());
747
+ ///
748
+ /// drop(strong); // But not any more.
749
+ /// assert!(weak.upgrade().is_none());
750
+ /// ```
751
+ pub fn upgrade ( & self ) -> Option < Dispatch > {
752
+ self . subscriber
753
+ . upgrade ( )
754
+ . map ( |subscriber| Dispatch { subscriber } )
755
+ }
756
+ }
757
+
758
+ impl fmt:: Debug for WeakDispatch {
759
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
760
+ let mut tuple = f. debug_tuple ( "WeakDispatch" ) ;
761
+ match self . subscriber . upgrade ( ) {
762
+ Some ( subscriber) => tuple. field ( & format_args ! ( "Some({:p})" , subscriber) ) ,
763
+ None => tuple. field ( & format_args ! ( "None" ) ) ,
764
+ } ;
765
+ tuple. finish ( )
766
+ }
767
+ }
768
+
685
769
#[ cfg( feature = "std" ) ]
686
770
impl Registrar {
687
771
pub ( crate ) fn upgrade ( & self ) -> Option < Dispatch > {
0 commit comments