crates/fuzzy/src/char_bag.rs 🔗
@@ -1,6 +1,6 @@
use std::iter::FromIterator;
-#[derive(Copy, Clone, Debug, Default)]
+#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct CharBag(u64);
impl CharBag {
Max Brunsfeld created
crates/fuzzy/src/char_bag.rs | 2
crates/gpui/src/executor.rs | 7 ++++
crates/project/src/worktree.rs | 34 ++++++++++++++++------
crates/server/src/rpc.rs | 52 +++++++++++++++++++++++++++++++---
crates/sum_tree/src/sum_tree.rs | 8 +++++
5 files changed, 88 insertions(+), 15 deletions(-)
@@ -1,6 +1,6 @@
use std::iter::FromIterator;
-#[derive(Copy, Clone, Debug, Default)]
+#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct CharBag(u64);
impl CharBag {
@@ -370,6 +370,13 @@ impl Foreground {
*any_value.downcast().unwrap()
}
+ pub fn run_until_parked(&self) {
+ match self {
+ Self::Deterministic { executor, .. } => executor.run_until_parked(),
+ _ => panic!("this method can only be called on a deterministic executor"),
+ }
+ }
+
pub fn parking_forbidden(&self) -> bool {
match self {
Self::Deterministic { executor, .. } => executor.state.lock().forbid_parking,
@@ -87,7 +87,7 @@ pub struct RemoteWorktree {
pending_updates: VecDeque<proto::UpdateWorktree>,
}
-#[derive(Clone)]
+#[derive(Clone, PartialEq, Eq)]
pub struct Snapshot {
id: WorktreeId,
root_name: String,
@@ -1315,13 +1315,29 @@ impl fmt::Debug for LocalWorktree {
impl fmt::Debug for Snapshot {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- for entry in self.entries_by_path.cursor::<()>() {
- for _ in entry.path.ancestors().skip(1) {
- write!(f, " ")?;
+ struct EntriesById<'a>(&'a SumTree<PathEntry>);
+ struct EntriesByPath<'a>(&'a SumTree<Entry>);
+
+ impl<'a> fmt::Debug for EntriesByPath<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_map()
+ .entries(self.0.iter().map(|entry| (&entry.path, entry.id)))
+ .finish()
}
- writeln!(f, "{:?} (inode: {})", entry.path, entry.inode)?;
}
- Ok(())
+
+ impl<'a> fmt::Debug for EntriesById<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_list().entries(self.0.iter()).finish()
+ }
+ }
+
+ f.debug_struct("Snapshot")
+ .field("id", &self.id)
+ .field("root_name", &self.root_name)
+ .field("entries_by_path", &EntriesByPath(&self.entries_by_path))
+ .field("entries_by_id", &EntriesById(&self.entries_by_id))
+ .finish()
}
}
@@ -1528,7 +1544,7 @@ impl File {
}
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Entry {
pub id: usize,
pub kind: EntryKind,
@@ -1539,7 +1555,7 @@ pub struct Entry {
pub is_ignored: bool,
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub enum EntryKind {
PendingDir,
Dir,
@@ -1642,7 +1658,7 @@ impl sum_tree::Summary for EntrySummary {
}
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq, Eq)]
struct PathEntry {
id: usize,
path: Arc<Path>,
@@ -1085,6 +1085,7 @@ mod tests {
github, AppState, Config,
};
use ::rpc::Peer;
+ use collections::BTreeMap;
use gpui::{executor, ModelHandle, TestAppContext};
use parking_lot::Mutex;
use postage::{mpsc, watch};
@@ -3597,11 +3598,11 @@ mod tests {
.unwrap();
clients.push(cx.foreground().spawn(host.simulate_host(
- host_project,
+ host_project.clone(),
operations.clone(),
max_operations,
rng.clone(),
- host_cx,
+ host_cx.clone(),
)));
while operations.get() < max_operations {
@@ -3647,10 +3648,51 @@ mod tests {
}
let clients = futures::future::join_all(clients).await;
+ cx.foreground().run_until_parked();
+
+ let host_worktree_snapshots = host_project.read_with(&host_cx, |project, cx| {
+ project
+ .worktrees(cx)
+ .map(|worktree| {
+ let snapshot = worktree.read(cx).snapshot();
+ (snapshot.id(), snapshot)
+ })
+ .collect::<BTreeMap<_, _>>()
+ });
+
for (ix, (client_a, cx_a)) in clients.iter().enumerate() {
- for buffer_a in &client_a.buffers {
- let buffer_id = buffer_a.read_with(cx_a, |buffer, _| buffer.remote_id());
- for (client_b, cx_b) in &clients[ix + 1..] {
+ let worktree_snapshots =
+ client_a
+ .project
+ .as_ref()
+ .unwrap()
+ .read_with(cx_a, |project, cx| {
+ project
+ .worktrees(cx)
+ .map(|worktree| {
+ let snapshot = worktree.read(cx).snapshot();
+ (snapshot.id(), snapshot)
+ })
+ .collect::<BTreeMap<_, _>>()
+ });
+
+ assert_eq!(
+ worktree_snapshots.keys().collect::<Vec<_>>(),
+ host_worktree_snapshots.keys().collect::<Vec<_>>(),
+ "guest {} has different worktrees than the host",
+ ix
+ );
+ for (id, snapshot) in &host_worktree_snapshots {
+ assert_eq!(
+ worktree_snapshots[id], *snapshot,
+ "guest {} has different snapshot than the host for worktree {}",
+ ix, id
+ );
+ }
+
+ for (client_b, cx_b) in &clients[ix + 1..] {
+ for buffer_a in &client_a.buffers {
+ let buffer_id = buffer_a.read_with(cx_a, |buffer, _| buffer.remote_id());
if let Some(buffer_b) = client_b.buffers.iter().find(|buffer| {
buffer.read_with(cx_b, |buffer, _| buffer.remote_id() == buffer_id)
}) {
@@ -478,6 +478,14 @@ impl<T: Item> SumTree<T> {
}
}
+impl<T: Item + PartialEq> PartialEq for SumTree<T> {
+ fn eq(&self, other: &Self) -> bool {
+ self.iter().eq(other.iter())
+ }
+}
+
+impl<T: Item + Eq> Eq for SumTree<T> {}
+
impl<T: KeyedItem> SumTree<T> {
pub fn insert_or_replace(&mut self, item: T, cx: &<T::Summary as Summary>::Context) -> bool {
let mut replaced = false;