mirror of
https://github.com/zed-industries/zed.git
synced 2025-02-10 04:09:37 +00:00
Merge branch 'zed2' of github.com:zed-industries/zed into zed2
This commit is contained in:
commit
98e2490807
3 changed files with 205 additions and 22 deletions
|
@ -1,12 +1,16 @@
|
|||
mod async_context;
|
||||
mod entity_map;
|
||||
mod model_context;
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
mod test_context;
|
||||
|
||||
pub use async_context::*;
|
||||
pub use entity_map::*;
|
||||
pub use model_context::*;
|
||||
use refineable::Refineable;
|
||||
use smallvec::SmallVec;
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub use test_context::*;
|
||||
|
||||
use crate::{
|
||||
current_platform, image_cache::ImageCache, Action, AnyBox, AnyView, AppMetadata, AssetSource,
|
||||
|
|
137
crates/gpui2/src/app/test_context.rs
Normal file
137
crates/gpui2/src/app/test_context.rs
Normal file
|
@ -0,0 +1,137 @@
|
|||
use crate::{
|
||||
AnyWindowHandle, AppContext, AsyncAppContext, Context, Executor, Handle, MainThread,
|
||||
ModelContext, Result, Task, WindowContext,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use std::{any::Any, future::Future, sync::Arc};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TestAppContext {
|
||||
pub(crate) app: Arc<Mutex<AppContext>>,
|
||||
pub(crate) executor: Executor,
|
||||
}
|
||||
|
||||
impl Context for TestAppContext {
|
||||
type EntityContext<'a, 'w, T> = ModelContext<'a, T>;
|
||||
type Result<T> = T;
|
||||
|
||||
fn entity<T: 'static>(
|
||||
&mut self,
|
||||
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
|
||||
) -> Self::Result<Handle<T>>
|
||||
where
|
||||
T: Any + Send + Sync,
|
||||
{
|
||||
let mut lock = self.app.lock();
|
||||
lock.entity(build_entity)
|
||||
}
|
||||
|
||||
fn update_entity<T: 'static, R>(
|
||||
&mut self,
|
||||
handle: &Handle<T>,
|
||||
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
|
||||
) -> Self::Result<R> {
|
||||
let mut lock = self.app.lock();
|
||||
lock.update_entity(handle, update)
|
||||
}
|
||||
}
|
||||
|
||||
impl TestAppContext {
|
||||
pub fn refresh(&mut self) -> Result<()> {
|
||||
let mut lock = self.app.lock();
|
||||
lock.refresh();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn executor(&self) -> &Executor {
|
||||
&self.executor
|
||||
}
|
||||
|
||||
pub fn update<R>(&self, f: impl FnOnce(&mut AppContext) -> R) -> Result<R> {
|
||||
let mut lock = self.app.lock();
|
||||
Ok(f(&mut *lock))
|
||||
}
|
||||
|
||||
pub fn read_window<R>(
|
||||
&self,
|
||||
handle: AnyWindowHandle,
|
||||
update: impl FnOnce(&WindowContext) -> R,
|
||||
) -> Result<R> {
|
||||
let mut app_context = self.app.lock();
|
||||
app_context.read_window(handle.id, update)
|
||||
}
|
||||
|
||||
pub fn update_window<R>(
|
||||
&self,
|
||||
handle: AnyWindowHandle,
|
||||
update: impl FnOnce(&mut WindowContext) -> R,
|
||||
) -> Result<R> {
|
||||
let mut app = self.app.lock();
|
||||
app.update_window(handle.id, update)
|
||||
}
|
||||
|
||||
pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static) -> Task<R>
|
||||
where
|
||||
Fut: Future<Output = R> + Send + 'static,
|
||||
R: Send + 'static,
|
||||
{
|
||||
let cx = self.to_async();
|
||||
self.executor.spawn(async move { f(cx).await })
|
||||
}
|
||||
|
||||
pub fn spawn_on_main<Fut, R>(
|
||||
&self,
|
||||
f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static,
|
||||
) -> Task<R>
|
||||
where
|
||||
Fut: Future<Output = R> + 'static,
|
||||
R: Send + 'static,
|
||||
{
|
||||
let cx = self.to_async();
|
||||
self.executor.spawn_on_main(|| f(cx))
|
||||
}
|
||||
|
||||
pub fn run_on_main<R>(
|
||||
&self,
|
||||
f: impl FnOnce(&mut MainThread<AppContext>) -> R + Send + 'static,
|
||||
) -> Result<Task<R>>
|
||||
where
|
||||
R: Send + 'static,
|
||||
{
|
||||
let mut app_context = self.app.lock();
|
||||
Ok(app_context.run_on_main(f))
|
||||
}
|
||||
|
||||
pub fn has_global<G: 'static>(&self) -> Result<bool> {
|
||||
let lock = self.app.lock();
|
||||
Ok(lock.has_global::<G>())
|
||||
}
|
||||
|
||||
pub fn read_global<G: 'static, R>(&self, read: impl FnOnce(&G, &AppContext) -> R) -> Result<R> {
|
||||
let lock = self.app.lock();
|
||||
Ok(read(lock.global(), &lock))
|
||||
}
|
||||
|
||||
pub fn try_read_global<G: 'static, R>(
|
||||
&self,
|
||||
read: impl FnOnce(&G, &AppContext) -> R,
|
||||
) -> Option<R> {
|
||||
let lock = self.app.lock();
|
||||
Some(read(lock.try_global()?, &lock))
|
||||
}
|
||||
|
||||
pub fn update_global<G: 'static, R>(
|
||||
&mut self,
|
||||
update: impl FnOnce(&mut G, &mut AppContext) -> R,
|
||||
) -> Result<R> {
|
||||
let mut lock = self.app.lock();
|
||||
Ok(lock.update_global(update))
|
||||
}
|
||||
|
||||
fn to_async(&self) -> AsyncAppContext {
|
||||
AsyncAppContext {
|
||||
app: Arc::downgrade(&self.app),
|
||||
executor: self.executor.clone(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,57 +1,87 @@
|
|||
use crate::PlatformDispatcher;
|
||||
use async_task::Runnable;
|
||||
use collections::{BTreeMap, VecDeque};
|
||||
use collections::{BTreeMap, HashMap, VecDeque};
|
||||
use parking_lot::Mutex;
|
||||
use rand::prelude::*;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{
|
||||
sync::Arc,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use util::post_inc;
|
||||
|
||||
pub struct TestDispatcher(Mutex<TestDispatcherState>);
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
struct TestDispatcherId(usize);
|
||||
|
||||
pub struct TestDispatcher {
|
||||
id: TestDispatcherId,
|
||||
state: Arc<Mutex<TestDispatcherState>>,
|
||||
}
|
||||
|
||||
struct TestDispatcherState {
|
||||
random: StdRng,
|
||||
foreground: VecDeque<Runnable>,
|
||||
foreground: HashMap<TestDispatcherId, VecDeque<Runnable>>,
|
||||
background: Vec<Runnable>,
|
||||
delayed: BTreeMap<Instant, Runnable>,
|
||||
time: Instant,
|
||||
is_main_thread: bool,
|
||||
next_id: TestDispatcherId,
|
||||
}
|
||||
|
||||
impl TestDispatcher {
|
||||
pub fn new(random: StdRng) -> Self {
|
||||
let state = TestDispatcherState {
|
||||
random,
|
||||
foreground: VecDeque::new(),
|
||||
foreground: HashMap::default(),
|
||||
background: Vec::new(),
|
||||
delayed: BTreeMap::new(),
|
||||
time: Instant::now(),
|
||||
is_main_thread: true,
|
||||
next_id: TestDispatcherId(1),
|
||||
};
|
||||
|
||||
TestDispatcher(Mutex::new(state))
|
||||
TestDispatcher {
|
||||
id: TestDispatcherId(0),
|
||||
state: Arc::new(Mutex::new(state)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for TestDispatcher {
|
||||
fn clone(&self) -> Self {
|
||||
let id = post_inc(&mut self.state.lock().next_id.0);
|
||||
Self {
|
||||
id: TestDispatcherId(id),
|
||||
state: self.state.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PlatformDispatcher for TestDispatcher {
|
||||
fn is_main_thread(&self) -> bool {
|
||||
self.0.lock().is_main_thread
|
||||
self.state.lock().is_main_thread
|
||||
}
|
||||
|
||||
fn dispatch(&self, runnable: Runnable) {
|
||||
self.0.lock().background.push(runnable);
|
||||
self.state.lock().background.push(runnable);
|
||||
}
|
||||
|
||||
fn dispatch_on_main_thread(&self, runnable: Runnable) {
|
||||
self.0.lock().foreground.push_back(runnable);
|
||||
self.state
|
||||
.lock()
|
||||
.foreground
|
||||
.entry(self.id)
|
||||
.or_default()
|
||||
.push_back(runnable);
|
||||
}
|
||||
|
||||
fn dispatch_after(&self, duration: std::time::Duration, runnable: Runnable) {
|
||||
let mut state = self.0.lock();
|
||||
let mut state = self.state.lock();
|
||||
let next_time = state.time + duration;
|
||||
state.delayed.insert(next_time, runnable);
|
||||
}
|
||||
|
||||
fn poll(&self) -> bool {
|
||||
let mut state = self.0.lock();
|
||||
let mut state = self.state.lock();
|
||||
|
||||
while let Some((deadline, _)) = state.delayed.first_key_value() {
|
||||
if *deadline > state.time {
|
||||
|
@ -61,36 +91,48 @@ impl PlatformDispatcher for TestDispatcher {
|
|||
state.background.push(runnable);
|
||||
}
|
||||
|
||||
if state.foreground.is_empty() && state.background.is_empty() {
|
||||
let foreground_len: usize = state
|
||||
.foreground
|
||||
.values()
|
||||
.map(|runnables| runnables.len())
|
||||
.sum();
|
||||
let background_len = state.background.len();
|
||||
|
||||
if foreground_len == 0 && background_len == 0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let foreground_len = state.foreground.len();
|
||||
let background_len = state.background.len();
|
||||
let main_thread = background_len == 0
|
||||
|| state
|
||||
.random
|
||||
.gen_ratio(foreground_len as u32, background_len as u32);
|
||||
let main_thread = state.random.gen_ratio(
|
||||
foreground_len as u32,
|
||||
(foreground_len + background_len) as u32,
|
||||
);
|
||||
let was_main_thread = state.is_main_thread;
|
||||
state.is_main_thread = main_thread;
|
||||
|
||||
let runnable = if main_thread {
|
||||
state.foreground.pop_front().unwrap()
|
||||
let state = &mut *state;
|
||||
let runnables = state
|
||||
.foreground
|
||||
.values_mut()
|
||||
.filter(|runnables| !runnables.is_empty())
|
||||
.choose(&mut state.random)
|
||||
.unwrap();
|
||||
runnables.pop_front().unwrap()
|
||||
} else {
|
||||
let ix = state.random.gen_range(0..background_len);
|
||||
state.background.remove(ix)
|
||||
state.background.swap_remove(ix)
|
||||
};
|
||||
|
||||
drop(state);
|
||||
runnable.run();
|
||||
|
||||
self.0.lock().is_main_thread = was_main_thread;
|
||||
self.state.lock().is_main_thread = was_main_thread;
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn advance_clock(&self, by: Duration) {
|
||||
self.0.lock().time += by;
|
||||
self.state.lock().time += by;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue