gpui_tokio.rs

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