#[cfg(feature = "std")]
use crate::stdlib::{
- cell::{Cell, RefCell},
+ cell::{Cell, RefCell, RefMut},
error,
};
can_enter: Cell<bool>,
}
+/// While this guard is active, additional calls to subscriber functions on
+/// the default dispatcher will not be able to access the dispatch context.
+/// Dropping the guard will allow the dispatch context to be re-entered.
+#[cfg(feature = "std")]
+struct Entered<'a>(&'a State);
+
/// A guard that resets the current default dispatcher to the prior
/// default dispatcher when dropped.
#[cfg(feature = "std")]
where
F: FnMut(&Dispatch) -> T,
{
- // While this guard is active, additional calls to subscriber functions on
- // the default dispatcher will not be able to access the dispatch context.
- // Dropping the guard will allow the dispatch context to be re-entered.
- struct Entered<'a>(&'a Cell<bool>);
- impl<'a> Drop for Entered<'a> {
- #[inline]
- fn drop(&mut self) {
- self.0.set(true);
- }
- }
-
CURRENT_STATE
.try_with(|state| {
- if state.can_enter.replace(false) {
- let _guard = Entered(&state.can_enter);
-
- let mut default = state.default.borrow_mut();
-
- if default.is::<NoSubscriber>() {
- if let Some(global) = get_global() {
- // don't redo this call on the next check
- *default = global.clone();
- }
- }
- f(&*default)
- } else {
- f(&Dispatch::none())
+ if let Some(entered) = state.enter() {
+ return f(&*entered.current());
}
+
+ f(&Dispatch::none())
})
.unwrap_or_else(|_| f(&Dispatch::none()))
}
+/// Executes a closure with a reference to this thread's current [dispatcher].
+///
+/// Note that calls to `get_default` should not be nested; if this function is
+/// called while inside of another `get_default`, that closure will be provided
+/// with `Dispatch::none` rather than the previously set dispatcher.
+///
+/// [dispatcher]: ../dispatcher/struct.Dispatch.html
+#[cfg(feature = "std")]
+#[doc(hidden)]
+#[inline(never)]
+pub fn get_current<T>(f: impl FnOnce(&Dispatch) -> T) -> Option<T> {
+ CURRENT_STATE
+ .try_with(|state| {
+ let entered = state.enter()?;
+ Some(f(&*entered.current()))
+ })
+ .ok()?
+}
+
+/// Executes a closure with a reference to the current [dispatcher].
+///
+/// [dispatcher]: ../dispatcher/struct.Dispatch.html
+#[cfg(not(feature = "std"))]
+#[doc(hidden)]
+pub fn get_current<T>(f: impl FnOnce(&Dispatch) -> T) -> Option<T> {
+ let dispatch = get_global()?;
+ Some(f(&dispatch))
+}
+
/// Executes a closure with a reference to the current [dispatcher].
///
/// [dispatcher]: ../dispatcher/struct.Dispatch.html
EXISTS.store(true, Ordering::Release);
DefaultGuard(prior)
}
+
+ #[inline]
+ fn enter(&self) -> Option<Entered<'_>> {
+ if self.can_enter.replace(false) {
+ Some(Entered(&self))
+ } else {
+ None
+ }
+ }
+}
+
+// ===== impl Entered =====
+
+#[cfg(feature = "std")]
+impl<'a> Entered<'a> {
+ #[inline]
+ fn current(&self) -> RefMut<'a, Dispatch> {
+ let mut default = self.0.default.borrow_mut();
+
+ if default.is::<NoSubscriber>() {
+ if let Some(global) = get_global() {
+ // don't redo this call on the next check
+ *default = global.clone();
+ }
+ }
+
+ default
+ }
+}
+
+#[cfg(feature = "std")]
+impl<'a> Drop for Entered<'a> {
+ #[inline]
+ fn drop(&mut self) {
+ self.0.can_enter.set(true);
+ }
}
// ===== impl DefaultGuard =====