diff --git a/Cargo.lock b/Cargo.lock index 851d49181ab0c292820dc36fb49ee05f8bbad436..a6752a55cefe7dec3516b96ee12198c3ba525c72 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -746,10 +746,10 @@ dependencies = [ "anyhow", "arrayvec 0.7.1", "clock", + "collections", "gpui", "log", "rand 0.8.3", - "seahash", "smallvec", "sum_tree", ] @@ -1057,6 +1057,13 @@ dependencies = [ "objc", ] +[[package]] +name = "collections" +version = "0.1.0" +dependencies = [ + "seahash", +] + [[package]] name = "color_quant" version = "1.1.0" @@ -5739,6 +5746,7 @@ dependencies = [ "async-tungstenite", "base64 0.13.0", "clap 3.0.0-beta.2", + "collections", "comrak", "either", "envy", diff --git a/crates/buffer/Cargo.toml b/crates/buffer/Cargo.toml index 3d2cc8eec0eb8377a97b8201d25a26957b7dc77f..b69627eb7339a5992a41a4c132f964d2409de44f 100644 --- a/crates/buffer/Cargo.toml +++ b/crates/buffer/Cargo.toml @@ -4,19 +4,19 @@ version = "0.1.0" edition = "2021" [features] -test-support = ["rand", "seahash"] +test-support = ["rand"] [dependencies] clock = { path = "../clock" } +collections = { path = "../collections" } sum_tree = { path = "../sum_tree" } anyhow = "1.0.38" arrayvec = "0.7.1" log = "0.4" rand = { version = "0.8.3", optional = true } -seahash = { version = "4.1", optional = true } smallvec = { version = "1.6", features = ["union"] } [dev-dependencies] +collections = { path = "../collections", features = ["test-support"] } gpui = { path = "../gpui", features = ["test-support"] } -seahash = "4.1" rand = "0.8.3" diff --git a/crates/buffer/src/lib.rs b/crates/buffer/src/lib.rs index 81288e7c41e0ca761664dda6a2ac261c34a11c4b..8c04fac9a6fe18a6a4c624ff7ac838523ee0d4ed 100644 --- a/crates/buffer/src/lib.rs +++ b/crates/buffer/src/lib.rs @@ -12,6 +12,7 @@ mod tests; pub use anchor::*; use anyhow::{anyhow, Result}; use clock::ReplicaId; +use collections::{HashMap, HashSet}; use operation_queue::OperationQueue; pub use point::*; pub use point_utf16::*; @@ -31,31 +32,6 @@ use std::{ pub use sum_tree::Bias; use sum_tree::{FilterCursor, SumTree}; -#[cfg(any(test, feature = "test-support"))] -#[derive(Clone, Default)] -pub struct DeterministicState; - -#[cfg(any(test, feature = "test-support"))] -impl std::hash::BuildHasher for DeterministicState { - type Hasher = seahash::SeaHasher; - - fn build_hasher(&self) -> Self::Hasher { - seahash::SeaHasher::new() - } -} - -#[cfg(any(test, feature = "test-support"))] -type HashMap = std::collections::HashMap; - -#[cfg(any(test, feature = "test-support"))] -type HashSet = std::collections::HashSet; - -#[cfg(not(any(test, feature = "test-support")))] -type HashMap = std::collections::HashMap; - -#[cfg(not(any(test, feature = "test-support")))] -type HashSet = std::collections::HashSet; - #[derive(Clone)] pub struct Buffer { fragments: SumTree, diff --git a/crates/chat_panel/src/lib.rs b/crates/chat_panel/src/lib.rs index d9d3ce64fa9590a0c643fdc3bdea014064a291c8..44c4bd6295adb4e43025ee1e2e00854761ec97b0 100644 --- a/crates/chat_panel/src/lib.rs +++ b/crates/chat_panel/src/lib.rs @@ -96,7 +96,7 @@ impl ChatPanel { }); let mut message_list = ListState::new(0, Orientation::Bottom, 1000., { - let this = cx.handle().downgrade(); + let this = cx.weak_handle(); move |ix, cx| { let this = this.upgrade(cx).unwrap().read(cx); let message = this.active_channel.as_ref().unwrap().0.read(cx).message(ix); diff --git a/crates/client/src/lib.rs b/crates/client/src/lib.rs index 1f3e2c008bc6c6a48965405c73f775f88d419464..652278d785116484bc5275e22427b87652963c32 100644 --- a/crates/client/src/lib.rs +++ b/crates/client/src/lib.rs @@ -272,7 +272,7 @@ impl Client { let subscription_id = (TypeId::of::(), Default::default()); let client = self.clone(); let mut state = self.state.write(); - let model = cx.handle().downgrade(); + let model = cx.weak_handle(); let prev_extractor = state .entity_id_extractors .insert(subscription_id.0, Box::new(|_| Default::default())); @@ -317,7 +317,7 @@ impl Client { let subscription_id = (TypeId::of::(), remote_id); let client = self.clone(); let mut state = self.state.write(); - let model = cx.handle().downgrade(); + let model = cx.weak_handle(); state .entity_id_extractors .entry(subscription_id.0) diff --git a/crates/collections/Cargo.toml b/crates/collections/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..b0b1a8bd3867eac134638896795aa9dc75e8f573 --- /dev/null +++ b/crates/collections/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "collections" +version = "0.1.0" +edition = "2021" + +[features] +test-support = ["seahash"] + +[dependencies] +seahash = { version = "4.1", optional = true } diff --git a/crates/collections/src/lib.rs b/crates/collections/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..acef74dbd64a326b82556a42326abef1df4f5da3 --- /dev/null +++ b/crates/collections/src/lib.rs @@ -0,0 +1,26 @@ +#[cfg(feature = "test-support")] +#[derive(Clone, Default)] +pub struct DeterministicState; + +#[cfg(feature = "test-support")] +impl std::hash::BuildHasher for DeterministicState { + type Hasher = seahash::SeaHasher; + + fn build_hasher(&self) -> Self::Hasher { + seahash::SeaHasher::new() + } +} + +#[cfg(feature = "test-support")] +pub type HashMap = std::collections::HashMap; + +#[cfg(feature = "test-support")] +pub type HashSet = std::collections::HashSet; + +#[cfg(not(feature = "test-support"))] +pub type HashMap = std::collections::HashMap; + +#[cfg(not(feature = "test-support"))] +pub type HashSet = std::collections::HashSet; + +pub use std::collections::*; diff --git a/crates/editor/src/lib.rs b/crates/editor/src/lib.rs index 4566badd9859b6ccb1bde33a34c975e7656a4829..2a893a25b0198f0b1759a012ce9c70ef28a6ee59 100644 --- a/crates/editor/src/lib.rs +++ b/crates/editor/src/lib.rs @@ -487,7 +487,7 @@ impl Editor { ) }); Self { - handle: cx.handle().downgrade(), + handle: cx.weak_handle(), buffer, display_map, selection_set_id, diff --git a/crates/file_finder/src/lib.rs b/crates/file_finder/src/lib.rs index 21280c2be502f33edfe599b02b2c12897bd5a868..8fef0b6bdf7e29692a08a233b883350e63275b20 100644 --- a/crates/file_finder/src/lib.rs +++ b/crates/file_finder/src/lib.rs @@ -286,7 +286,7 @@ impl FileFinder { .detach(); Self { - handle: cx.handle().downgrade(), + handle: cx.weak_handle(), settings, project, query_editor, diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 0e2e313db04a9393a85ad5e58fec3b3977559929..d731167edc24f3602624c92832bfdd514eeeb9ca 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -342,10 +342,8 @@ impl App { fn update T>(&mut self, callback: F) -> T { let mut state = self.0.borrow_mut(); - state.pending_flushes += 1; - let result = callback(&mut *state); + let result = state.update(callback); state.pending_notifications.clear(); - state.flush_effects(); result } } @@ -406,11 +404,7 @@ impl TestAppContext { T: Entity, F: FnOnce(&mut ModelContext) -> T, { - let mut state = self.cx.borrow_mut(); - state.pending_flushes += 1; - let handle = state.add_model(build_model); - state.flush_effects(); - handle + self.cx.borrow_mut().add_model(build_model) } pub fn add_window(&mut self, build_root_view: F) -> (usize, ViewHandle) @@ -436,11 +430,7 @@ impl TestAppContext { T: View, F: FnOnce(&mut ViewContext) -> T, { - let mut state = self.cx.borrow_mut(); - state.pending_flushes += 1; - let handle = state.add_view(window_id, build_view); - state.flush_effects(); - handle + self.cx.borrow_mut().add_view(window_id, build_view) } pub fn add_option_view( @@ -452,11 +442,7 @@ impl TestAppContext { T: View, F: FnOnce(&mut ViewContext) -> Option, { - let mut state = self.cx.borrow_mut(); - state.pending_flushes += 1; - let handle = state.add_option_view(window_id, build_view); - state.flush_effects(); - handle + self.cx.borrow_mut().add_option_view(window_id, build_view) } pub fn read T>(&self, callback: F) -> T { @@ -535,11 +521,7 @@ impl AsyncAppContext { } pub fn update T>(&mut self, callback: F) -> T { - let mut state = self.0.borrow_mut(); - state.pending_flushes += 1; - let result = callback(&mut *state); - state.flush_effects(); - result + self.0.borrow_mut().update(callback) } pub fn add_model(&mut self, build_model: F) -> ModelHandle @@ -569,11 +551,7 @@ impl UpdateModel for AsyncAppContext { handle: &ModelHandle, update: &mut dyn FnMut(&mut E, &mut ModelContext) -> O, ) -> O { - let mut state = self.0.borrow_mut(); - state.pending_flushes += 1; - let result = state.update_model(handle, update); - state.flush_effects(); - result + self.0.borrow_mut().update_model(handle, update) } } @@ -607,11 +585,7 @@ impl UpdateView for AsyncAppContext { where T: View, { - let mut state = self.0.borrow_mut(); - state.pending_flushes += 1; - let result = state.update_view(handle, update); - state.flush_effects(); - result + self.0.borrow_mut().update_view(handle, update) } } @@ -636,11 +610,7 @@ impl UpdateModel for TestAppContext { handle: &ModelHandle, update: &mut dyn FnMut(&mut T, &mut ModelContext) -> O, ) -> O { - let mut state = self.cx.borrow_mut(); - state.pending_flushes += 1; - let result = state.update_model(handle, update); - state.flush_effects(); - result + self.cx.borrow_mut().update_model(handle, update) } } @@ -665,11 +635,7 @@ impl UpdateView for TestAppContext { where T: View, { - let mut state = self.cx.borrow_mut(); - state.pending_flushes += 1; - let result = state.update_view(handle, update); - state.flush_effects(); - result + self.cx.borrow_mut().update_view(handle, update) } } @@ -727,6 +693,7 @@ impl MutableAppContext { foreground_platform: Rc, font_cache: Arc, asset_source: impl AssetSource, + // entity_drop_tx: ) -> Self { Self { weak_self: None, @@ -941,9 +908,9 @@ impl MutableAppContext { .collect() } - pub fn update T>(&mut self, callback: F) -> T { + pub fn update T>(&mut self, callback: F) -> T { self.pending_flushes += 1; - let result = callback(); + let result = callback(self); self.flush_effects(); result } @@ -1124,46 +1091,44 @@ impl MutableAppContext { path: &[usize], action: &dyn AnyAction, ) -> bool { - self.pending_flushes += 1; - let mut halted_dispatch = false; - - for view_id in path.iter().rev() { - if let Some(mut view) = self.cx.views.remove(&(window_id, *view_id)) { - let type_id = view.as_any().type_id(); - - if let Some((name, mut handlers)) = self - .actions - .get_mut(&type_id) - .and_then(|h| h.remove_entry(&action.id())) - { - for handler in handlers.iter_mut().rev() { - let halt_dispatch = - handler(view.as_mut(), action, self, window_id, *view_id); - if halt_dispatch { - halted_dispatch = true; - break; + self.update(|this| { + let mut halted_dispatch = false; + for view_id in path.iter().rev() { + if let Some(mut view) = this.cx.views.remove(&(window_id, *view_id)) { + let type_id = view.as_any().type_id(); + + if let Some((name, mut handlers)) = this + .actions + .get_mut(&type_id) + .and_then(|h| h.remove_entry(&action.id())) + { + for handler in handlers.iter_mut().rev() { + let halt_dispatch = + handler(view.as_mut(), action, this, window_id, *view_id); + if halt_dispatch { + halted_dispatch = true; + break; + } } + this.actions + .get_mut(&type_id) + .unwrap() + .insert(name, handlers); } - self.actions - .get_mut(&type_id) - .unwrap() - .insert(name, handlers); - } - self.cx.views.insert((window_id, *view_id), view); + this.cx.views.insert((window_id, *view_id), view); - if halted_dispatch { - break; + if halted_dispatch { + break; + } } } - } - if !halted_dispatch { - self.dispatch_global_action_any(action); - } - - self.flush_effects(); - halted_dispatch + if !halted_dispatch { + this.dispatch_global_action_any(action); + } + halted_dispatch + }) } pub fn dispatch_global_action(&mut self, action: A) { @@ -1171,14 +1136,14 @@ impl MutableAppContext { } fn dispatch_global_action_any(&mut self, action: &dyn AnyAction) { - if let Some((name, mut handlers)) = self.global_actions.remove_entry(&action.id()) { - self.pending_flushes += 1; - for handler in handlers.iter_mut().rev() { - handler(action, self); + self.update(|this| { + if let Some((name, mut handlers)) = this.global_actions.remove_entry(&action.id()) { + for handler in handlers.iter_mut().rev() { + handler(action, this); + } + this.global_actions.insert(name, handlers); } - self.global_actions.insert(name, handlers); - self.flush_effects(); - } + }) } pub fn add_bindings>(&mut self, bindings: T) { @@ -1230,14 +1195,14 @@ impl MutableAppContext { T: Entity, F: FnOnce(&mut ModelContext) -> T, { - self.pending_flushes += 1; - let model_id = post_inc(&mut self.next_entity_id); - let handle = ModelHandle::new(model_id, &self.cx.ref_counts); - let mut cx = ModelContext::new(self, model_id); - let model = build_model(&mut cx); - self.cx.models.insert(model_id, Box::new(model)); - self.flush_effects(); - handle + self.update(|this| { + let model_id = post_inc(&mut this.next_entity_id); + let handle = ModelHandle::new(model_id, &this.cx.ref_counts); + let mut cx = ModelContext::new(this, model_id); + let model = build_model(&mut cx); + this.cx.models.insert(model_id, Box::new(model)); + handle + }) } pub fn add_window( @@ -1249,26 +1214,26 @@ impl MutableAppContext { T: View, F: FnOnce(&mut ViewContext) -> T, { - self.pending_flushes += 1; - let window_id = post_inc(&mut self.next_window_id); - let root_view = self.add_view(window_id, build_root_view); + self.update(|this| { + let window_id = post_inc(&mut this.next_window_id); + let root_view = this.add_view(window_id, build_root_view); - self.cx.windows.insert( - window_id, - Window { - root_view: root_view.clone().into(), - focused_view_id: root_view.id(), - invalidation: None, - }, - ); - self.open_platform_window(window_id, window_options); - root_view.update(self, |view, cx| { - view.on_focus(cx); - cx.notify(); - }); - self.flush_effects(); + this.cx.windows.insert( + window_id, + Window { + root_view: root_view.clone().into(), + focused_view_id: root_view.id(), + invalidation: None, + }, + ); + this.open_platform_window(window_id, window_options); + root_view.update(this, |view, cx| { + view.on_focus(cx); + cx.notify(); + }); - (window_id, root_view) + (window_id, root_view) + }) } pub fn remove_window(&mut self, window_id: usize) { @@ -1377,25 +1342,25 @@ impl MutableAppContext { T: View, F: FnOnce(&mut ViewContext) -> Option, { - let view_id = post_inc(&mut self.next_entity_id); - self.pending_flushes += 1; - let handle = ViewHandle::new(window_id, view_id, &self.cx.ref_counts); - let mut cx = ViewContext::new(self, window_id, view_id); - let handle = if let Some(view) = build_view(&mut cx) { - self.cx.views.insert((window_id, view_id), Box::new(view)); - if let Some(window) = self.cx.windows.get_mut(&window_id) { - window - .invalidation - .get_or_insert_with(Default::default) - .updated - .insert(view_id); - } - Some(handle) - } else { - None - }; - self.flush_effects(); - handle + self.update(|this| { + let view_id = post_inc(&mut this.next_entity_id); + let handle = ViewHandle::new(window_id, view_id, &this.cx.ref_counts); + let mut cx = ViewContext::new(this, window_id, view_id); + let handle = if let Some(view) = build_view(&mut cx) { + this.cx.views.insert((window_id, view_id), Box::new(view)); + if let Some(window) = this.cx.windows.get_mut(&window_id) { + window + .invalidation + .get_or_insert_with(Default::default) + .updated + .insert(view_id); + } + Some(handle) + } else { + None + }; + handle + }) } pub fn element_state( @@ -1647,27 +1612,25 @@ impl MutableAppContext { return; } - self.pending_flushes += 1; - - let blurred_id = self.cx.windows.get_mut(&window_id).map(|window| { - let blurred_id = window.focused_view_id; - window.focused_view_id = focused_id; - blurred_id - }); + self.update(|this| { + let blurred_id = this.cx.windows.get_mut(&window_id).map(|window| { + let blurred_id = window.focused_view_id; + window.focused_view_id = focused_id; + blurred_id + }); - if let Some(blurred_id) = blurred_id { - if let Some(mut blurred_view) = self.cx.views.remove(&(window_id, blurred_id)) { - blurred_view.on_blur(self, window_id, blurred_id); - self.cx.views.insert((window_id, blurred_id), blurred_view); + if let Some(blurred_id) = blurred_id { + if let Some(mut blurred_view) = this.cx.views.remove(&(window_id, blurred_id)) { + blurred_view.on_blur(this, window_id, blurred_id); + this.cx.views.insert((window_id, blurred_id), blurred_view); + } } - } - - if let Some(mut focused_view) = self.cx.views.remove(&(window_id, focused_id)) { - focused_view.on_focus(self, window_id, focused_id); - self.cx.views.insert((window_id, focused_id), focused_view); - } - self.flush_effects(); + if let Some(mut focused_view) = this.cx.views.remove(&(window_id, focused_id)) { + focused_view.on_focus(this, window_id, focused_id); + this.cx.views.insert((window_id, focused_id), focused_view); + } + }) } pub fn spawn(&self, f: F) -> Task @@ -1713,18 +1676,18 @@ impl UpdateModel for MutableAppContext { update: &mut dyn FnMut(&mut T, &mut ModelContext) -> V, ) -> V { if let Some(mut model) = self.cx.models.remove(&handle.model_id) { - self.pending_flushes += 1; - let mut cx = ModelContext::new(self, handle.model_id); - let result = update( - model - .as_any_mut() - .downcast_mut() - .expect("downcast is type safe"), - &mut cx, - ); - self.cx.models.insert(handle.model_id, model); - self.flush_effects(); - result + self.update(|this| { + let mut cx = ModelContext::new(this, handle.model_id); + let result = update( + model + .as_any_mut() + .downcast_mut() + .expect("downcast is type safe"), + &mut cx, + ); + this.cx.models.insert(handle.model_id, model); + result + }) } else { panic!("circular model update"); } @@ -1759,25 +1722,25 @@ impl UpdateView for MutableAppContext { where T: View, { - self.pending_flushes += 1; - let mut view = self - .cx - .views - .remove(&(handle.window_id, handle.view_id)) - .expect("circular view update"); - - let mut cx = ViewContext::new(self, handle.window_id, handle.view_id); - let result = update( - view.as_any_mut() - .downcast_mut() - .expect("downcast is type safe"), - &mut cx, - ); - self.cx - .views - .insert((handle.window_id, handle.view_id), view); - self.flush_effects(); - result + self.update(|this| { + let mut view = this + .cx + .views + .remove(&(handle.window_id, handle.view_id)) + .expect("circular view update"); + + let mut cx = ViewContext::new(this, handle.window_id, handle.view_id); + let result = update( + view.as_any_mut() + .downcast_mut() + .expect("downcast is type safe"), + &mut cx, + ); + this.cx + .views + .insert((handle.window_id, handle.view_id), view); + result + }) } } @@ -2110,7 +2073,7 @@ impl<'a, T: Entity> ModelContext<'a, T> { S::Event: 'static, F: 'static + FnMut(&mut T, ModelHandle, &S::Event, &mut ModelContext), { - let subscriber = self.handle().downgrade(); + let subscriber = self.weak_handle(); self.app .subscribe_internal(handle, move |emitter, event, cx| { if let Some(subscriber) = subscriber.upgrade(cx) { @@ -2129,7 +2092,7 @@ impl<'a, T: Entity> ModelContext<'a, T> { S: Entity, F: 'static + FnMut(&mut T, ModelHandle, &mut ModelContext), { - let observer = self.handle().downgrade(); + let observer = self.weak_handle(); self.app.observe_internal(handle, move |observed, cx| { if let Some(observer) = observer.upgrade(cx) { observer.update(cx, |observer, cx| { @@ -2146,6 +2109,10 @@ impl<'a, T: Entity> ModelContext<'a, T> { ModelHandle::new(self.model_id, &self.app.cx.ref_counts) } + pub fn weak_handle(&self) -> WeakModelHandle { + WeakModelHandle::new(self.model_id) + } + pub fn spawn(&self, f: F) -> Task where F: FnOnce(ModelHandle, AsyncAppContext) -> Fut, @@ -2162,7 +2129,7 @@ impl<'a, T: Entity> ModelContext<'a, T> { Fut: 'static + Future, S: 'static, { - let handle = self.handle().downgrade(); + let handle = self.weak_handle(); self.app.spawn(|cx| f(handle, cx)) } } @@ -2241,6 +2208,10 @@ impl<'a, T: View> ViewContext<'a, T> { ViewHandle::new(self.window_id, self.view_id, &self.app.cx.ref_counts) } + pub fn weak_handle(&self) -> WeakViewHandle { + WeakViewHandle::new(self.window_id, self.view_id) + } + pub fn window_id(&self) -> usize { self.window_id } @@ -2336,7 +2307,7 @@ impl<'a, T: View> ViewContext<'a, T> { H: Handle, F: 'static + FnMut(&mut T, H, &E::Event, &mut ViewContext), { - let subscriber = self.handle().downgrade(); + let subscriber = self.weak_handle(); self.app .subscribe_internal(handle, move |emitter, event, cx| { if let Some(subscriber) = subscriber.upgrade(cx) { @@ -2356,7 +2327,7 @@ impl<'a, T: View> ViewContext<'a, T> { H: Handle, F: 'static + FnMut(&mut T, H, &mut ViewContext), { - let observer = self.handle().downgrade(); + let observer = self.weak_handle(); self.app.observe_internal(handle, move |observed, cx| { if let Some(observer) = observer.upgrade(cx) { observer.update(cx, |observer, cx| { @@ -2400,7 +2371,7 @@ impl<'a, T: View> ViewContext<'a, T> { Fut: 'static + Future, S: 'static, { - let handle = self.handle().downgrade(); + let handle = self.weak_handle(); self.app.spawn(|cx| f(handle, cx)) } } @@ -3328,7 +3299,9 @@ struct RefCounts { impl RefCounts { fn inc_model(&mut self, model_id: usize) { match self.entity_counts.entry(model_id) { - Entry::Occupied(mut entry) => *entry.get_mut() += 1, + Entry::Occupied(mut entry) => { + *entry.get_mut() += 1; + } Entry::Vacant(entry) => { entry.insert(1); self.dropped_models.remove(&model_id); @@ -3395,16 +3368,11 @@ impl RefCounts { HashSet<(usize, usize)>, HashSet<(TypeId, ElementStateId)>, ) { - let mut dropped_models = HashSet::new(); - let mut dropped_views = HashSet::new(); - let mut dropped_element_states = HashSet::new(); - std::mem::swap(&mut self.dropped_models, &mut dropped_models); - std::mem::swap(&mut self.dropped_views, &mut dropped_views); - std::mem::swap( - &mut self.dropped_element_states, - &mut dropped_element_states, - ); - (dropped_models, dropped_views, dropped_element_states) + ( + std::mem::take(&mut self.dropped_models), + std::mem::take(&mut self.dropped_views), + std::mem::take(&mut self.dropped_element_states), + ) } } @@ -3711,7 +3679,7 @@ mod tests { assert!(!*model_released.lock()); assert!(!*view_released.lock()); - cx.update(move || { + cx.update(move |_| { drop(model); }); assert!(*model_released.lock()); @@ -3817,7 +3785,7 @@ mod tests { cx.subscribe(&observed_model, |_, _, _, _| {}).detach(); }); - cx.update(|| { + cx.update(|_| { drop(observing_view); drop(observing_model); }); @@ -3909,7 +3877,7 @@ mod tests { cx.observe(&observed_model, |_, _, _| {}).detach(); }); - cx.update(|| { + cx.update(|_| { drop(observing_view); drop(observing_model); }); diff --git a/crates/gpui/src/views/select.rs b/crates/gpui/src/views/select.rs index a76f156ebfe0fd31ec842b351680063d6a2d1e50..d7deea6d553da0360f327ca560343f65e167bf24 100644 --- a/crates/gpui/src/views/select.rs +++ b/crates/gpui/src/views/select.rs @@ -42,7 +42,7 @@ impl Select { render_item: F, ) -> Self { Self { - handle: cx.handle().downgrade(), + handle: cx.weak_handle(), render_item: Box::new(render_item), selected_item_ix: 0, item_count, diff --git a/crates/project_panel/src/lib.rs b/crates/project_panel/src/lib.rs index 4d05ed317a8e5fd0091f1f5b936ecbbcf18e9255..d8ce1df3c7ee2af1a713cdd17a048ce12f862cfc 100644 --- a/crates/project_panel/src/lib.rs +++ b/crates/project_panel/src/lib.rs @@ -108,7 +108,7 @@ impl ProjectPanel { visible_entries: Default::default(), expanded_dir_ids: Default::default(), selection: None, - handle: cx.handle().downgrade(), + handle: cx.weak_handle(), }; this.update_visible_entries(None, cx); this diff --git a/crates/server/Cargo.toml b/crates/server/Cargo.toml index 2d9f2b2c6537a9fb7383478e5f31064d38bd9de9..e5e2b61a6af9f3745b03165ef9f81a9097c8698a 100644 --- a/crates/server/Cargo.toml +++ b/crates/server/Cargo.toml @@ -13,6 +13,7 @@ name = "seed" required-features = ["seed-support"] [dependencies] +collections = { path = "../collections" } rpc = { path = "../rpc" } anyhow = "1.0.40" @@ -54,6 +55,7 @@ version = "0.5.2" features = ["runtime-async-std-rustls", "postgres", "time", "uuid"] [dev-dependencies] +collections = { path = "../collections", features = ["test-support"] } gpui = { path = "../gpui" } zed = { path = "../zed", features = ["test-support"] } diff --git a/crates/server/src/rpc.rs b/crates/server/src/rpc.rs index ab406966c1695b0b747379df500d261311c69c22..54440bbd56faa2bf46d18c82a5513d3cd74250df 100644 --- a/crates/server/src/rpc.rs +++ b/crates/server/src/rpc.rs @@ -8,6 +8,7 @@ use super::{ use anyhow::anyhow; use async_std::task; use async_tungstenite::{tungstenite::protocol::Role, WebSocketStream}; +use collections::{HashMap, HashSet}; use futures::{future::BoxFuture, FutureExt}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use postage::{mpsc, prelude::Sink as _, prelude::Stream as _}; @@ -16,14 +17,7 @@ use rpc::{ Connection, ConnectionId, Peer, TypedEnvelope, }; use sha1::{Digest as _, Sha1}; -use std::{ - any::TypeId, - collections::{HashMap, HashSet}, - future::Future, - mem, - sync::Arc, - time::Instant, -}; +use std::{any::TypeId, future::Future, mem, sync::Arc, time::Instant}; use store::{Store, Worktree}; use surf::StatusCode; use tide::log; @@ -220,7 +214,7 @@ impl Server { let receipt = request.receipt(); let host_user_id = self.state().user_id_for_connection(request.sender_id)?; - let mut contact_user_ids = HashSet::new(); + let mut contact_user_ids = HashSet::default(); contact_user_ids.insert(host_user_id); for github_login in request.payload.authorized_logins { match self.app_state.db.create_user(&github_login, false).await { @@ -2238,6 +2232,12 @@ mod tests { }) .await; + worktree_a + .condition(&cx_a, |worktree, cx| { + worktree.collaborators().contains_key(&client_b.peer_id) + }) + .await; + cx_a.update(move |_| drop(worktree_a)); client_a .user_store diff --git a/crates/server/src/rpc/store.rs b/crates/server/src/rpc/store.rs index 77bb01702fa3988d3ecdc1bd8f612c9ea673a915..2062683b7cda8de04e8d06d6667c5d9ee994435a 100644 --- a/crates/server/src/rpc/store.rs +++ b/crates/server/src/rpc/store.rs @@ -1,7 +1,8 @@ use crate::db::{ChannelId, UserId}; use anyhow::anyhow; +use collections::{HashMap, HashSet}; use rpc::{proto, ConnectionId}; -use std::collections::{hash_map, HashMap, HashSet}; +use std::collections::hash_map; #[derive(Default)] pub struct Store { @@ -172,15 +173,15 @@ impl Store { } pub fn contacts_for_user(&self, user_id: UserId) -> Vec { - let mut contacts = HashMap::new(); + let mut contacts = HashMap::default(); for worktree_id in self .visible_worktrees_by_user_id .get(&user_id) - .unwrap_or(&HashSet::new()) + .unwrap_or(&HashSet::default()) { let worktree = &self.worktrees[worktree_id]; - let mut guests = HashSet::new(); + let mut guests = HashSet::default(); if let Ok(share) = worktree.share() { for guest_connection_id in share.guests.keys() { if let Ok(user_id) = self.user_id_for_connection(*guest_connection_id) {