Skip to main content

libasync_dispatcher/
current_dispatcher.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::{AsAsyncDispatcherRef, AsyncDispatcher, AsyncDispatcherRef, GetAsyncDispatcher};
6use libasync_sys::*;
7use std::ptr::{NonNull, null};
8
9/// A placeholder for the currently active dispatcher. Use
10/// [`GetAsyncDispatcher::get_async_dispatcher`] to access it when needed.
11#[derive(Clone, Copy, Debug, Default, PartialEq)]
12pub struct CurrentDispatcher;
13
14impl CurrentDispatcher {
15    /// Sets the currently active dispatcher for this thread.
16    ///
17    /// # Safety
18    ///
19    /// The caller must ensure that the dispatcher they set will be alive until it is [`Self::unset`]
20    /// or [`Self::set`] to another value. Using [`Self::with`] is a safer way to use this api as
21    /// it will use the current execution stack to ensure that it is properly unset.
22    pub unsafe fn set(dispatcher: &impl AsAsyncDispatcherRef) {
23        let dispatcher = dispatcher.as_async_dispatcher_ref();
24        // SAFETY: The caller promises that the dispatcher will live as long as it is set as the default.
25        unsafe { async_set_default_dispatcher(dispatcher.0.as_ptr()) };
26    }
27
28    /// Unsets the currently active dispatcher whatever it is.
29    pub fn unset() {
30        // SAFETY: It is always safe to unset the current dispatcher, as the worst that can happen
31        // is the set dispatcher is leaked.
32        unsafe { async_set_default_dispatcher(null()) }
33    }
34
35    /// Runs the passed function with the current dispatcher set to the one passed in, and then
36    /// re-sets the dispatcher to whatever it was before.
37    pub fn with<R>(dispatcher: &impl AsAsyncDispatcherRef, f: impl FnOnce() -> R) -> R {
38        let old = async_get_default_dispatcher();
39        // SAFETY: We will reset the dispatcher below.
40        unsafe { Self::set(dispatcher) };
41        let ret = f();
42        // SAFETY: The dispatcher being set was set prior to entering this function, so something
43        // else is responsible for ensuring that it was valid before and after this function is
44        // called. We are only returning to the status quo.
45        unsafe { async_set_default_dispatcher(old) }
46        ret
47    }
48}
49
50impl GetAsyncDispatcher for CurrentDispatcher {
51    fn try_get_async_dispatcher(&self) -> Option<AsyncDispatcher> {
52        let dispatcher = NonNull::new(async_get_default_dispatcher().cast_mut())?;
53        // SAFETY: NonNull::new will null-check that we have a current dispatcher, and the contract
54        // of async-default is that the dispatcher set should be valid.
55        Some(AsyncDispatcher::new(&unsafe { AsyncDispatcherRef::from_raw(dispatcher) }))
56    }
57}