Make the gpui_tokio crate generic over the context it spawns (#23995)
Part of #21092 Makes `Tokio::spawn` generic over any `AppContext`. Also removes a stray `model_context` I missed Release Notes: - N/A
This commit is contained in:
parent
ff43b6875b
commit
517e519bdc
7 changed files with 133 additions and 18 deletions
|
@ -22,9 +22,9 @@ use slotmap::SlotMap;
|
||||||
|
|
||||||
pub use async_context::*;
|
pub use async_context::*;
|
||||||
use collections::{FxHashMap, FxHashSet, HashMap, VecDeque};
|
use collections::{FxHashMap, FxHashSet, HashMap, VecDeque};
|
||||||
|
pub use context::*;
|
||||||
pub use entity_map::*;
|
pub use entity_map::*;
|
||||||
use http_client::HttpClient;
|
use http_client::HttpClient;
|
||||||
pub use model_context::*;
|
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
pub use test_context::*;
|
pub use test_context::*;
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
|
@ -41,8 +41,8 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
mod async_context;
|
mod async_context;
|
||||||
|
mod context;
|
||||||
mod entity_map;
|
mod entity_map;
|
||||||
mod model_context;
|
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
mod test_context;
|
mod test_context;
|
||||||
|
|
||||||
|
@ -1667,6 +1667,21 @@ impl AppContext for App {
|
||||||
|
|
||||||
Ok(read(view, self))
|
Ok(read(view, self))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
|
||||||
|
where
|
||||||
|
R: Send + 'static,
|
||||||
|
{
|
||||||
|
self.background_executor.spawn(future)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> Self::Result<R>
|
||||||
|
where
|
||||||
|
G: Global,
|
||||||
|
{
|
||||||
|
let mut g = self.global::<G>();
|
||||||
|
callback(&g, self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// These effects are processed at the end of each application update cycle.
|
/// These effects are processed at the end of each application update cycle.
|
||||||
|
|
|
@ -104,6 +104,22 @@ impl AppContext for AsyncApp {
|
||||||
let lock = app.borrow();
|
let lock = app.borrow();
|
||||||
lock.read_window(window, read)
|
lock.read_window(window, read)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
|
||||||
|
where
|
||||||
|
R: Send + 'static,
|
||||||
|
{
|
||||||
|
self.background_executor.spawn(future)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> Self::Result<R>
|
||||||
|
where
|
||||||
|
G: Global,
|
||||||
|
{
|
||||||
|
let app = self.app.upgrade().context("app was released")?;
|
||||||
|
let mut lock = app.borrow_mut();
|
||||||
|
Ok(lock.update(|this| this.read_global(callback)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsyncApp {
|
impl AsyncApp {
|
||||||
|
@ -367,6 +383,20 @@ impl AppContext for AsyncWindowContext {
|
||||||
{
|
{
|
||||||
self.app.read_window(window, read)
|
self.app.read_window(window, read)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
|
||||||
|
where
|
||||||
|
R: Send + 'static,
|
||||||
|
{
|
||||||
|
self.app.background_executor.spawn(future)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> Result<R>
|
||||||
|
where
|
||||||
|
G: Global,
|
||||||
|
{
|
||||||
|
self.app.read_global(callback)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VisualContext for AsyncWindowContext {
|
impl VisualContext for AsyncWindowContext {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
AnyView, AnyWindowHandle, App, AppContext, AsyncApp, DispatchPhase, Effect, EntityId,
|
AnyView, AnyWindowHandle, AppContext, AsyncApp, DispatchPhase, Effect, EntityId, EventEmitter,
|
||||||
EventEmitter, FocusHandle, FocusOutEvent, Focusable, Global, KeystrokeObserver, Reservation,
|
FocusHandle, FocusOutEvent, Focusable, Global, KeystrokeObserver, Reservation, SubscriberSet,
|
||||||
SubscriberSet, Subscription, Task, WeakEntity, WeakFocusHandle, Window, WindowHandle,
|
Subscription, Task, WeakEntity, WeakFocusHandle, Window, WindowHandle,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
|
@ -13,7 +13,7 @@ use std::{
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AsyncWindowContext, Entity, KeystrokeEvent};
|
use super::{App, AsyncWindowContext, Entity, KeystrokeEvent};
|
||||||
|
|
||||||
/// The app context, with specialized behavior for the given model.
|
/// The app context, with specialized behavior for the given model.
|
||||||
#[derive(Deref, DerefMut)]
|
#[derive(Deref, DerefMut)]
|
||||||
|
@ -717,6 +717,20 @@ impl<'a, T> AppContext for Context<'a, T> {
|
||||||
{
|
{
|
||||||
self.app.read_window(window, read)
|
self.app.read_window(window, read)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
|
||||||
|
where
|
||||||
|
R: Send + 'static,
|
||||||
|
{
|
||||||
|
self.app.background_executor.spawn(future)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> Self::Result<R>
|
||||||
|
where
|
||||||
|
G: Global,
|
||||||
|
{
|
||||||
|
self.app.read_global(callback)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Borrow<App> for Context<'_, T> {
|
impl<T> Borrow<App> for Context<'_, T> {
|
|
@ -94,6 +94,21 @@ impl AppContext for TestAppContext {
|
||||||
let app = self.app.borrow();
|
let app = self.app.borrow();
|
||||||
app.read_window(window, read)
|
app.read_window(window, read)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
|
||||||
|
where
|
||||||
|
R: Send + 'static,
|
||||||
|
{
|
||||||
|
self.background_executor.spawn(future)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> Self::Result<R>
|
||||||
|
where
|
||||||
|
G: Global,
|
||||||
|
{
|
||||||
|
let app = self.app.borrow();
|
||||||
|
app.read_global(callback)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestAppContext {
|
impl TestAppContext {
|
||||||
|
@ -906,6 +921,20 @@ impl AppContext for VisualTestContext {
|
||||||
{
|
{
|
||||||
self.cx.read_window(window, read)
|
self.cx.read_window(window, read)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
|
||||||
|
where
|
||||||
|
R: Send + 'static,
|
||||||
|
{
|
||||||
|
self.cx.background_spawn(future)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> Self::Result<R>
|
||||||
|
where
|
||||||
|
G: Global,
|
||||||
|
{
|
||||||
|
self.cx.read_global(callback)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VisualContext for VisualTestContext {
|
impl VisualContext for VisualTestContext {
|
||||||
|
|
|
@ -155,7 +155,7 @@ pub use util::arc_cow::ArcCow;
|
||||||
pub use view::*;
|
pub use view::*;
|
||||||
pub use window::*;
|
pub use window::*;
|
||||||
|
|
||||||
use std::{any::Any, borrow::BorrowMut};
|
use std::{any::Any, borrow::BorrowMut, future::Future};
|
||||||
use taffy::TaffyLayoutEngine;
|
use taffy::TaffyLayoutEngine;
|
||||||
|
|
||||||
/// The context trait, allows the different contexts in GPUI to be used
|
/// The context trait, allows the different contexts in GPUI to be used
|
||||||
|
@ -215,6 +215,16 @@ pub trait AppContext {
|
||||||
) -> Result<R>
|
) -> Result<R>
|
||||||
where
|
where
|
||||||
T: 'static;
|
T: 'static;
|
||||||
|
|
||||||
|
/// Spawn a future on a background thread
|
||||||
|
fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
|
||||||
|
where
|
||||||
|
R: Send + 'static;
|
||||||
|
|
||||||
|
/// Read a global from this app context
|
||||||
|
fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> Self::Result<R>
|
||||||
|
where
|
||||||
|
G: Global;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returned by [Context::reserve_entity] to later be passed to [Context::insert_model].
|
/// Returned by [Context::reserve_entity] to later be passed to [Context::insert_model].
|
||||||
|
|
|
@ -81,6 +81,20 @@ pub fn derive_app_context(input: TokenStream) -> TokenStream {
|
||||||
{
|
{
|
||||||
self.#app_variable.read_window(window, read)
|
self.#app_variable.read_window(window, read)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn background_spawn<R>(&self, future: impl std::future::Future<Output = R> + Send + 'static) -> gpui::Task<R>
|
||||||
|
where
|
||||||
|
R: Send + 'static,
|
||||||
|
{
|
||||||
|
self.#app_variable.background_spawn(future)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_global<G, R>(&self, callback: impl FnOnce(&G, &gpui::App) -> R) -> Self::Result<R>
|
||||||
|
where
|
||||||
|
G: gpui::Global,
|
||||||
|
{
|
||||||
|
self.#app_variable.read_global(callback)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
use gpui::{App, Global, ReadGlobal, Task};
|
use gpui::{App, AppContext, Global, ReadGlobal, Task};
|
||||||
use tokio::task::JoinError;
|
use tokio::task::JoinError;
|
||||||
use util::defer;
|
use util::defer;
|
||||||
|
|
||||||
|
@ -32,21 +32,24 @@ pub struct Tokio {}
|
||||||
impl Tokio {
|
impl Tokio {
|
||||||
/// Spawns the given future on Tokio's thread pool, and returns it via a GPUI task
|
/// 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
|
/// Note that the Tokio task will be cancelled if the GPUI task is dropped
|
||||||
pub fn spawn<Fut, R>(cx: &mut App, f: Fut) -> Task<Result<R, JoinError>>
|
pub fn spawn<C, Fut, R>(cx: &mut C, f: Fut) -> C::Result<Task<Result<R, JoinError>>>
|
||||||
where
|
where
|
||||||
|
C: AppContext,
|
||||||
Fut: Future<Output = R> + Send + 'static,
|
Fut: Future<Output = R> + Send + 'static,
|
||||||
R: Send + 'static,
|
R: Send + 'static,
|
||||||
{
|
{
|
||||||
let join_handle = GlobalTokio::global(cx).runtime.spawn(f);
|
cx.read_global(|tokio: &GlobalTokio, cx| {
|
||||||
|
let join_handle = tokio.runtime.spawn(f);
|
||||||
let abort_handle = join_handle.abort_handle();
|
let abort_handle = join_handle.abort_handle();
|
||||||
let cancel = defer(move || {
|
let cancel = defer(move || {
|
||||||
abort_handle.abort();
|
abort_handle.abort();
|
||||||
});
|
});
|
||||||
cx.background_executor().spawn(async move {
|
cx.background_spawn(async move {
|
||||||
let result = join_handle.await;
|
let result = join_handle.await;
|
||||||
drop(cancel);
|
drop(cancel);
|
||||||
result
|
result
|
||||||
})
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle(cx: &mut App) -> tokio::runtime::Handle {
|
pub fn handle(cx: &mut App) -> tokio::runtime::Handle {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue