selection_capture/async_api.rs
1use crate::traits::{AppAdapter, AppProfileStore, CancelSignal, CapturePlatform};
2use crate::types::{CaptureOptions, CaptureOutcome};
3
4/// Async wrapper around [`crate::capture`].
5///
6/// On a **multi-thread** Tokio runtime this uses `block_in_place` to offload
7/// the blocking work to the current thread without stalling other tasks.
8///
9/// On a **current-thread** (`LocalSet`) runtime `block_in_place` is unavailable
10/// because there is only one worker thread. In that case the underlying sync
11/// call runs directly on the async task thread and will block the executor for
12/// its duration. If you are using a current-thread runtime, call the
13/// synchronous [`crate::capture`] API from a `spawn_blocking` closure at the
14/// call site instead — that avoids blocking all other tasks on the runtime.
15pub async fn capture_async(
16 platform: &impl CapturePlatform,
17 store: &impl AppProfileStore,
18 cancel: &impl CancelSignal,
19 adapters: &[&dyn AppAdapter],
20 options: &CaptureOptions,
21) -> CaptureOutcome {
22 match tokio::runtime::Handle::try_current() {
23 Ok(handle) if handle.runtime_flavor() == tokio::runtime::RuntimeFlavor::MultiThread => {
24 tokio::task::block_in_place(|| {
25 crate::capture(platform, store, cancel, adapters, options)
26 })
27 }
28 // Current-thread or no-runtime path: run synchronously.
29 // NOTE: This blocks the executor thread for the duration of the capture.
30 // See the function-level doc comment for the recommended workaround.
31 Ok(_) | Err(_) => crate::capture(platform, store, cancel, adapters, options),
32 }
33}