103 lines
3.2 KiB
Rust
103 lines
3.2 KiB
Rust
//! Vendored from zed's `crates/gpui_tokio` (Apache-2.0) because the `gpui-pre` family
|
|
//! does not republish it, and `nostr-sdk`'s reqwest client needs a Tokio runtime.
|
|
|
|
use std::future::Future;
|
|
|
|
use gpui::{App, AppContext, Global, ReadGlobal, Task};
|
|
use gpui_util::defer;
|
|
pub use tokio::task::JoinError;
|
|
|
|
/// Initializes the Tokio wrapper using a new Tokio runtime with 2 worker threads.
|
|
///
|
|
/// If you need more threads (or access to the runtime outside of GPUI), you can create the runtime
|
|
/// yourself and pass a Handle to `init_from_handle`.
|
|
pub fn init(cx: &mut App) {
|
|
let runtime = tokio::runtime::Builder::new_multi_thread()
|
|
// Since we now have two executors, let's try to keep our footprint small
|
|
.worker_threads(2)
|
|
.enable_all()
|
|
.build()
|
|
.expect("Failed to initialize Tokio");
|
|
|
|
let handle = runtime.handle().clone();
|
|
cx.set_global(GlobalTokio {
|
|
owned_runtime: Some(runtime),
|
|
handle,
|
|
});
|
|
}
|
|
|
|
/// Initializes the Tokio wrapper using a Tokio runtime handle.
|
|
pub fn init_from_handle(cx: &mut App, handle: tokio::runtime::Handle) {
|
|
cx.set_global(GlobalTokio {
|
|
owned_runtime: None,
|
|
handle,
|
|
});
|
|
}
|
|
|
|
struct GlobalTokio {
|
|
owned_runtime: Option<tokio::runtime::Runtime>,
|
|
handle: tokio::runtime::Handle,
|
|
}
|
|
|
|
impl Global for GlobalTokio {}
|
|
|
|
impl Drop for GlobalTokio {
|
|
fn drop(&mut self) {
|
|
if let Some(runtime) = self.owned_runtime.take() {
|
|
runtime.shutdown_background();
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct Tokio {}
|
|
|
|
impl Tokio {
|
|
/// Spawns the given future on Tokio's thread pool, and returns it via a GPUI task
|
|
/// Note that the Tokio task will be cancelled if the GPUI task is dropped
|
|
pub fn spawn<C, Fut, R>(cx: &C, f: Fut) -> Task<Result<R, JoinError>>
|
|
where
|
|
C: AppContext,
|
|
Fut: Future<Output = R> + Send + 'static,
|
|
R: Send + 'static,
|
|
{
|
|
cx.read_global(|tokio: &GlobalTokio, cx| {
|
|
let join_handle = tokio.handle.spawn(f);
|
|
let abort_handle = join_handle.abort_handle();
|
|
let cancel = defer(move || {
|
|
abort_handle.abort();
|
|
});
|
|
cx.background_spawn(async move {
|
|
let result = join_handle.await;
|
|
drop(cancel);
|
|
result
|
|
})
|
|
})
|
|
}
|
|
|
|
/// Spawns the given future on Tokio's thread pool, and returns it via a GPUI task
|
|
/// Note that the Tokio task will be cancelled if the GPUI task is dropped
|
|
pub fn spawn_result<C, Fut, R>(cx: &C, f: Fut) -> Task<anyhow::Result<R>>
|
|
where
|
|
C: AppContext,
|
|
Fut: Future<Output = anyhow::Result<R>> + Send + 'static,
|
|
R: Send + 'static,
|
|
{
|
|
cx.read_global(|tokio: &GlobalTokio, cx| {
|
|
let join_handle = tokio.handle.spawn(f);
|
|
let abort_handle = join_handle.abort_handle();
|
|
let cancel = defer(move || {
|
|
abort_handle.abort();
|
|
});
|
|
cx.background_spawn(async move {
|
|
let result = join_handle.await?;
|
|
drop(cancel);
|
|
result
|
|
})
|
|
})
|
|
}
|
|
|
|
pub fn handle(cx: &App) -> tokio::runtime::Handle {
|
|
GlobalTokio::global(cx).handle.clone()
|
|
}
|
|
}
|