gpui_tokio.rs

 1use std::future::Future;
 2
 3use gpui::{App, AppContext, Global, ReadGlobal, Task};
 4use util::defer;
 5
 6pub use tokio::task::JoinError;
 7
 8pub fn init(cx: &mut App) {
 9    cx.set_global(GlobalTokio::new());
10}
11
12struct GlobalTokio {
13    runtime: tokio::runtime::Runtime,
14}
15
16impl Global for GlobalTokio {}
17
18impl GlobalTokio {
19    fn new() -> Self {
20        let runtime = tokio::runtime::Builder::new_multi_thread()
21            // Since we now have two executors, let's try to keep our footprint small
22            .worker_threads(2)
23            .enable_all()
24            .build()
25            .expect("Failed to initialize Tokio");
26
27        Self { runtime }
28    }
29}
30
31pub struct Tokio {}
32
33impl Tokio {
34    /// Spawns the given future on Tokio's thread pool, and returns it via a GPUI task
35    /// Note that the Tokio task will be cancelled if the GPUI task is dropped
36    pub fn spawn<C, Fut, R>(cx: &C, f: Fut) -> C::Result<Task<Result<R, JoinError>>>
37    where
38        C: AppContext,
39        Fut: Future<Output = R> + Send + 'static,
40        R: Send + 'static,
41    {
42        cx.read_global(|tokio: &GlobalTokio, cx| {
43            let join_handle = tokio.runtime.spawn(f);
44            let abort_handle = join_handle.abort_handle();
45            let cancel = defer(move || {
46                abort_handle.abort();
47            });
48            cx.background_spawn(async move {
49                let result = join_handle.await;
50                drop(cancel);
51                result
52            })
53        })
54    }
55
56    /// Spawns the given future on Tokio's thread pool, and returns it via a GPUI task
57    /// Note that the Tokio task will be cancelled if the GPUI task is dropped
58    pub fn spawn_result<C, Fut, R>(cx: &C, f: Fut) -> C::Result<Task<anyhow::Result<R>>>
59    where
60        C: AppContext,
61        Fut: Future<Output = anyhow::Result<R>> + Send + 'static,
62        R: Send + 'static,
63    {
64        cx.read_global(|tokio: &GlobalTokio, cx| {
65            let join_handle = tokio.runtime.spawn(f);
66            let abort_handle = join_handle.abort_handle();
67            let cancel = defer(move || {
68                abort_handle.abort();
69            });
70            cx.background_spawn(async move {
71                let result = join_handle.await?;
72                drop(cancel);
73                result
74            })
75        })
76    }
77
78    pub fn handle(cx: &App) -> tokio::runtime::Handle {
79        GlobalTokio::global(cx).runtime.handle().clone()
80    }
81}