Merge branch 'main' into go-to-line2

This commit is contained in:
Conrad Irwin
2023-11-08 14:46:52 -07:00
147 changed files with 32668 additions and 79 deletions
+137 -6
View File
@@ -16,8 +16,8 @@ pub use test_context::*;
use crate::{
current_platform, image_cache::ImageCache, Action, AnyBox, AnyView, AnyWindowHandle,
AppMetadata, AssetSource, BackgroundExecutor, ClipboardItem, Context, DispatchPhase, DisplayId,
Entity, FocusEvent, FocusHandle, FocusId, ForegroundExecutor, KeyBinding, Keymap, LayoutId,
PathPromptOptions, Pixels, Platform, PlatformDisplay, Point, Render, SubscriberSet,
Entity, EventEmitter, FocusEvent, FocusHandle, FocusId, ForegroundExecutor, KeyBinding, Keymap,
LayoutId, PathPromptOptions, Pixels, Platform, PlatformDisplay, Point, Render, SubscriberSet,
Subscription, SvgRenderer, Task, TextStyle, TextStyleRefinement, TextSystem, View, Window,
WindowContext, WindowHandle, WindowId,
};
@@ -48,15 +48,19 @@ pub struct AppCell {
impl AppCell {
#[track_caller]
pub fn borrow(&self) -> AppRef {
// let thread_id = std::thread::current().id();
// eprintln!("borrowed {thread_id:?}");
if let Some(_) = option_env!("TRACK_THREAD_BORROWS") {
let thread_id = std::thread::current().id();
eprintln!("borrowed {thread_id:?}");
}
AppRef(self.app.borrow())
}
#[track_caller]
pub fn borrow_mut(&self) -> AppRefMut {
// let thread_id = std::thread::current().id();
// eprintln!("borrowed {thread_id:?}");
if let Some(_) = option_env!("TRACK_THREAD_BORROWS") {
let thread_id = std::thread::current().id();
eprintln!("borrowed {thread_id:?}");
}
AppRefMut(self.app.borrow_mut())
}
}
@@ -64,9 +68,27 @@ impl AppCell {
#[derive(Deref, DerefMut)]
pub struct AppRef<'a>(Ref<'a, AppContext>);
impl<'a> Drop for AppRef<'a> {
fn drop(&mut self) {
if let Some(_) = option_env!("TRACK_THREAD_BORROWS") {
let thread_id = std::thread::current().id();
eprintln!("dropped borrow from {thread_id:?}");
}
}
}
#[derive(Deref, DerefMut)]
pub struct AppRefMut<'a>(RefMut<'a, AppContext>);
impl<'a> Drop for AppRefMut<'a> {
fn drop(&mut self) {
if let Some(_) = option_env!("TRACK_THREAD_BORROWS") {
let thread_id = std::thread::current().id();
eprintln!("dropped {thread_id:?}");
}
}
}
pub struct App(Rc<AppCell>);
/// Represents an application before it is fully launched. Once your app is
@@ -291,6 +313,83 @@ impl AppContext {
result
}
pub fn observe<W, E>(
&mut self,
entity: &E,
mut on_notify: impl FnMut(E, &mut AppContext) + 'static,
) -> Subscription
where
W: 'static,
E: Entity<W>,
{
self.observe_internal(entity, move |e, cx| {
on_notify(e, cx);
true
})
}
pub fn observe_internal<W, E>(
&mut self,
entity: &E,
mut on_notify: impl FnMut(E, &mut AppContext) -> bool + 'static,
) -> Subscription
where
W: 'static,
E: Entity<W>,
{
let entity_id = entity.entity_id();
let handle = entity.downgrade();
self.observers.insert(
entity_id,
Box::new(move |cx| {
if let Some(handle) = E::upgrade_from(&handle) {
on_notify(handle, cx)
} else {
false
}
}),
)
}
pub fn subscribe<T, E>(
&mut self,
entity: &E,
mut on_event: impl FnMut(E, &T::Event, &mut AppContext) + 'static,
) -> Subscription
where
T: 'static + EventEmitter,
E: Entity<T>,
{
self.subscribe_internal(entity, move |entity, event, cx| {
on_event(entity, event, cx);
true
})
}
pub(crate) fn subscribe_internal<T, E>(
&mut self,
entity: &E,
mut on_event: impl FnMut(E, &T::Event, &mut AppContext) -> bool + 'static,
) -> Subscription
where
T: 'static + EventEmitter,
E: Entity<T>,
{
let entity_id = entity.entity_id();
let entity = entity.downgrade();
self.event_listeners.insert(
entity_id,
Box::new(move |event, cx| {
let event: &T::Event = event.downcast_ref().expect("invalid event type");
if let Some(handle) = E::upgrade_from(&entity) {
on_event(handle, event, cx)
} else {
false
}
}),
)
}
pub fn windows(&self) -> Vec<AnyWindowHandle> {
self.windows
.values()
@@ -624,6 +723,7 @@ impl AppContext {
}
/// Access the global of the given type. Panics if a global for that type has not been assigned.
#[track_caller]
pub fn global<G: 'static>(&self) -> &G {
self.globals_by_type
.get(&TypeId::of::<G>())
@@ -640,6 +740,7 @@ impl AppContext {
}
/// Access the global of the given type mutably. Panics if a global for that type has not been assigned.
#[track_caller]
pub fn global_mut<G: 'static>(&mut self) -> &mut G {
let global_type = TypeId::of::<G>();
self.push_effect(Effect::NotifyGlobalObservers { global_type });
@@ -669,6 +770,24 @@ impl AppContext {
self.globals_by_type.insert(global_type, Box::new(global));
}
/// Clear all stored globals. Does not notify global observers.
#[cfg(any(test, feature = "test-support"))]
pub fn clear_globals(&mut self) {
self.globals_by_type.drain();
}
/// Remove the global of the given type from the app context. Does not notify global observers.
#[cfg(any(test, feature = "test-support"))]
pub fn remove_global<G: Any>(&mut self) -> G {
let global_type = TypeId::of::<G>();
*self
.globals_by_type
.remove(&global_type)
.unwrap_or_else(|| panic!("no global added for {}", std::any::type_name::<G>()))
.downcast()
.unwrap()
}
/// Update the global of the given type with a closure. Unlike `global_mut`, this method provides
/// your closure with mutable access to the `AppContext` and the global simultaneously.
pub fn update_global<G: 'static, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R {
@@ -828,6 +947,18 @@ impl Context for AppContext {
Ok(result)
})
}
fn read_model<T, R>(
&self,
handle: &Model<T>,
read: impl FnOnce(&T, &AppContext) -> R,
) -> Self::Result<R>
where
T: 'static,
{
let entity = self.entities.read(handle);
read(entity, self)
}
}
/// These effects are processed at the end of each application update cycle.
+24
View File
@@ -45,6 +45,19 @@ impl Context for AsyncAppContext {
Ok(app.update_model(handle, update))
}
fn read_model<T, R>(
&self,
handle: &Model<T>,
callback: impl FnOnce(&T, &AppContext) -> R,
) -> Self::Result<R>
where
T: 'static,
{
let app = self.app.upgrade().context("app was released")?;
let lock = app.borrow();
Ok(lock.read_model(handle, callback))
}
fn update_window<T, F>(&mut self, window: AnyWindowHandle, f: F) -> Result<T>
where
F: FnOnce(AnyView, &mut WindowContext<'_>) -> T,
@@ -226,6 +239,17 @@ impl Context for AsyncWindowContext {
{
self.app.update_window(window, update)
}
fn read_model<T, R>(
&self,
handle: &Model<T>,
read: impl FnOnce(&T, &AppContext) -> R,
) -> Self::Result<R>
where
T: 'static,
{
self.app.read_model(handle, read)
}
}
impl VisualContext for AsyncWindowContext {
+8
View File
@@ -325,6 +325,14 @@ impl<T: 'static> Model<T> {
cx.entities.read(self)
}
pub fn read_with<'a, R, C: Context>(
&self,
cx: &'a C,
f: impl FnOnce(&T, &AppContext) -> R,
) -> C::Result<R> {
cx.read_model(self, f)
}
/// Update the entity referenced by this model with the given function.
///
/// The update function receives a context appropriate for its environment.
+27 -27
View File
@@ -49,19 +49,14 @@ impl<'a, T: 'static> ModelContext<'a, T> {
E: Entity<W>,
{
let this = self.weak_model();
let entity_id = entity.entity_id();
let handle = entity.downgrade();
self.app.observers.insert(
entity_id,
Box::new(move |cx| {
if let Some((this, handle)) = this.upgrade().zip(E::upgrade_from(&handle)) {
this.update(cx, |this, cx| on_notify(this, handle, cx));
true
} else {
false
}
}),
)
self.app.observe_internal(entity, move |e, cx| {
if let Some(this) = this.upgrade() {
this.update(cx, |this, cx| on_notify(this, e, cx));
true
} else {
false
}
})
}
pub fn subscribe<T2, E>(
@@ -75,20 +70,14 @@ impl<'a, T: 'static> ModelContext<'a, T> {
E: Entity<T2>,
{
let this = self.weak_model();
let entity_id = entity.entity_id();
let entity = entity.downgrade();
self.app.event_listeners.insert(
entity_id,
Box::new(move |event, cx| {
let event: &T2::Event = event.downcast_ref().expect("invalid event type");
if let Some((this, handle)) = this.upgrade().zip(E::upgrade_from(&entity)) {
this.update(cx, |this, cx| on_event(this, handle, event, cx));
true
} else {
false
}
}),
)
self.app.subscribe_internal(entity, move |e, event, cx| {
if let Some(this) = this.upgrade() {
this.update(cx, |this, cx| on_event(this, e, event, cx));
true
} else {
false
}
})
}
pub fn on_release(
@@ -236,6 +225,17 @@ impl<'a, T> Context for ModelContext<'a, T> {
{
self.app.update_window(window, update)
}
fn read_model<U, R>(
&self,
handle: &Model<U>,
read: impl FnOnce(&U, &AppContext) -> R,
) -> Self::Result<R>
where
U: 'static,
{
self.app.read_model(handle, read)
}
}
impl<T> Borrow<AppContext> for ModelContext<'_, T> {
+37 -4
View File
@@ -1,7 +1,8 @@
use crate::{
AnyView, AnyWindowHandle, AppCell, AppContext, AsyncAppContext, BackgroundExecutor, Context,
EventEmitter, ForegroundExecutor, InputEvent, KeyDownEvent, Keystroke, Model, ModelContext,
Result, Task, TestDispatcher, TestPlatform, WindowContext,
Render, Result, Task, TestDispatcher, TestPlatform, ViewContext, VisualContext, WindowContext,
WindowHandle, WindowOptions,
};
use anyhow::{anyhow, bail};
use futures::{Stream, StreamExt};
@@ -12,6 +13,7 @@ pub struct TestAppContext {
pub app: Rc<AppCell>,
pub background_executor: BackgroundExecutor,
pub foreground_executor: ForegroundExecutor,
pub dispatcher: TestDispatcher,
}
impl Context for TestAppContext {
@@ -44,13 +46,25 @@ impl Context for TestAppContext {
let mut lock = self.app.borrow_mut();
lock.update_window(window, f)
}
fn read_model<T, R>(
&self,
handle: &Model<T>,
read: impl FnOnce(&T, &AppContext) -> R,
) -> Self::Result<R>
where
T: 'static,
{
let app = self.app.borrow();
app.read_model(handle, read)
}
}
impl TestAppContext {
pub fn new(dispatcher: TestDispatcher) -> Self {
let dispatcher = Arc::new(dispatcher);
let background_executor = BackgroundExecutor::new(dispatcher.clone());
let foreground_executor = ForegroundExecutor::new(dispatcher);
let arc_dispatcher = Arc::new(dispatcher.clone());
let background_executor = BackgroundExecutor::new(arc_dispatcher.clone());
let foreground_executor = ForegroundExecutor::new(arc_dispatcher);
let platform = Rc::new(TestPlatform::new(
background_executor.clone(),
foreground_executor.clone(),
@@ -61,9 +75,14 @@ impl TestAppContext {
app: AppContext::new(platform, asset_source, http_client),
background_executor,
foreground_executor,
dispatcher: dispatcher.clone(),
}
}
pub fn new_app(&self) -> TestAppContext {
Self::new(self.dispatcher.clone())
}
pub fn quit(&self) {
self.app.borrow_mut().quit();
}
@@ -87,6 +106,20 @@ impl TestAppContext {
cx.update(f)
}
pub fn read<R>(&self, f: impl FnOnce(&AppContext) -> R) -> R {
let cx = self.app.borrow();
f(&*cx)
}
pub fn add_window<F, V>(&mut self, build_window: F) -> WindowHandle<V>
where
F: FnOnce(&mut ViewContext<V>) -> V,
V: Render,
{
let mut cx = self.app.borrow_mut();
cx.open_window(WindowOptions::default(), |cx| cx.build_view(build_window))
}
pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncAppContext) -> Fut) -> Task<R>
where
Fut: Future<Output = R> + 'static,
+10
View File
@@ -17,6 +17,9 @@ use std::{
use util::TryFutureExt;
use waker_fn::waker_fn;
#[cfg(any(test, feature = "test-support"))]
use rand::rngs::StdRng;
#[derive(Clone)]
pub struct BackgroundExecutor {
dispatcher: Arc<dyn PlatformDispatcher>,
@@ -95,6 +98,7 @@ impl BackgroundExecutor {
}
#[cfg(any(test, feature = "test-support"))]
#[track_caller]
pub fn block_test<R>(&self, future: impl Future<Output = R>) -> R {
self.block_internal(false, future)
}
@@ -103,6 +107,7 @@ impl BackgroundExecutor {
self.block_internal(true, future)
}
#[track_caller]
pub(crate) fn block_internal<R>(
&self,
background_only: bool,
@@ -226,6 +231,11 @@ impl BackgroundExecutor {
self.dispatcher.as_test().unwrap().allow_parking();
}
#[cfg(any(test, feature = "test-support"))]
pub fn rng(&self) -> StdRng {
self.dispatcher.as_test().unwrap().rng()
}
pub fn num_cpus(&self) -> usize {
num_cpus::get()
}
+8
View File
@@ -93,6 +93,14 @@ pub trait Context {
where
T: 'static;
fn read_model<T, R>(
&self,
handle: &Model<T>,
read: impl FnOnce(&T, &AppContext) -> R,
) -> Self::Result<R>
where
T: 'static;
fn update_window<T, F>(&mut self, window: AnyWindowHandle, f: F) -> Result<T>
where
F: FnOnce(AnyView, &mut WindowContext<'_>) -> T;
@@ -127,6 +127,10 @@ impl TestDispatcher {
b
})
}
pub fn rng(&self) -> StdRng {
self.state.lock().random.clone()
}
}
impl Clone for TestDispatcher {
+23
View File
@@ -1391,6 +1391,18 @@ impl Context for WindowContext<'_> {
window.update(self.app, update)
}
}
fn read_model<T, R>(
&self,
handle: &Model<T>,
read: impl FnOnce(&T, &AppContext) -> R,
) -> Self::Result<R>
where
T: 'static,
{
let entity = self.entities.read(handle);
read(&*entity, &*self.app)
}
}
impl VisualContext for WindowContext<'_> {
@@ -2076,6 +2088,17 @@ impl<V> Context for ViewContext<'_, V> {
{
self.window_cx.update_window(window, update)
}
fn read_model<T, R>(
&self,
handle: &Model<T>,
read: impl FnOnce(&T, &AppContext) -> R,
) -> Self::Result<R>
where
T: 'static,
{
self.window_cx.read_model(handle, read)
}
}
impl<V: 'static> VisualContext for ViewContext<'_, V> {