Introduce a collections crate w/ deterministic hashmap, hashset in tests

Max Brunsfeld and Nathan Sobo created

Co-Authored-By: Nathan Sobo <nathan@zed.dev>

Change summary

Cargo.lock                     | 10 +++++++++-
crates/buffer/Cargo.toml       |  6 +++---
crates/buffer/src/lib.rs       | 26 +-------------------------
crates/collections/Cargo.toml  | 10 ++++++++++
crates/collections/src/lib.rs  | 26 ++++++++++++++++++++++++++
crates/server/Cargo.toml       |  2 ++
crates/server/src/rpc.rs       | 12 +++---------
crates/server/src/rpc/store.rs |  9 +++++----
8 files changed, 59 insertions(+), 42 deletions(-)

Detailed changes

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",

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"

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<K, V> = std::collections::HashMap<K, V, DeterministicState>;
-
-#[cfg(any(test, feature = "test-support"))]
-type HashSet<T> = std::collections::HashSet<T, DeterministicState>;
-
-#[cfg(not(any(test, feature = "test-support")))]
-type HashMap<K, V> = std::collections::HashMap<K, V>;
-
-#[cfg(not(any(test, feature = "test-support")))]
-type HashSet<T> = std::collections::HashSet<T>;
-
 #[derive(Clone)]
 pub struct Buffer {
     fragments: SumTree<Fragment>,

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 }

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<K, V> = std::collections::HashMap<K, V, DeterministicState>;
+
+#[cfg(feature = "test-support")]
+pub type HashSet<T> = std::collections::HashSet<T, DeterministicState>;
+
+#[cfg(not(feature = "test-support"))]
+pub type HashMap<K, V> = std::collections::HashMap<K, V>;
+
+#[cfg(not(feature = "test-support"))]
+pub type HashSet<T> = std::collections::HashSet<T>;
+
+pub use std::collections::*;

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"] }
 

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 {

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<proto::Contact> {
-        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) {