From e41c3a7c925387ca2c2441b4f41c963b95bc828d Mon Sep 17 00:00:00 2001
From: mo8it <mo8it@proton.me>
Date: Thu, 8 Aug 2024 23:46:21 +0200
Subject: [PATCH] Use fixed seeds with ahash

---
 Cargo.lock         | 12 ------------
 Cargo.toml         |  2 +-
 src/app_state.rs   |  4 ++--
 src/collections.rs | 10 ++++++++++
 src/dev/check.rs   |  8 ++++----
 src/main.rs        |  1 +
 6 files changed, 18 insertions(+), 19 deletions(-)
 create mode 100644 src/collections.rs

diff --git a/Cargo.lock b/Cargo.lock
index 86d35c5d..a61ba597 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -9,7 +9,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
 dependencies = [
  "cfg-if",
- "getrandom",
  "once_cell",
  "version_check",
  "zerocopy",
@@ -263,17 +262,6 @@ dependencies = [
  "libc",
 ]
 
-[[package]]
-name = "getrandom"
-version = "0.2.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi",
-]
-
 [[package]]
 name = "hashbrown"
 version = "0.14.5"
diff --git a/Cargo.toml b/Cargo.toml
index 456f738d..2cd2ebad 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -46,7 +46,7 @@ include = [
 ]
 
 [dependencies]
-ahash = "0.8.11"
+ahash = { version = "0.8.11", default-features = false }
 anyhow = "1.0.86"
 clap = { version = "4.5.13", features = ["derive"] }
 notify-debouncer-mini = { version = "0.4.1", default-features = false }
diff --git a/src/app_state.rs b/src/app_state.rs
index ac45bfc6..b72469c4 100644
--- a/src/app_state.rs
+++ b/src/app_state.rs
@@ -1,4 +1,3 @@
-use ahash::{HashSet, HashSetExt};
 use anyhow::{bail, Context, Error, Result};
 use std::{
     fs::{self, File},
@@ -11,6 +10,7 @@ use std::{
 use crate::{
     clear_terminal,
     cmd::CmdRunner,
+    collections::hash_set_with_capacity,
     embedded::EMBEDDED_FILES,
     exercise::{Exercise, RunnableExercise},
     info_file::ExerciseInfo,
@@ -70,7 +70,7 @@ impl AppState {
             return StateFileStatus::NotRead;
         }
 
-        let mut done_exercises = HashSet::with_capacity(self.exercises.len());
+        let mut done_exercises = hash_set_with_capacity(self.exercises.len());
 
         for done_exerise_name in lines {
             if done_exerise_name.is_empty() {
diff --git a/src/collections.rs b/src/collections.rs
new file mode 100644
index 00000000..fa9e3fa7
--- /dev/null
+++ b/src/collections.rs
@@ -0,0 +1,10 @@
+use ahash::AHasher;
+use std::hash::BuildHasherDefault;
+
+/// DOS attacks aren't a concern for Rustlings. Therefore, we use `ahash` with fixed seeds.
+pub type HashSet<T> = std::collections::HashSet<T, BuildHasherDefault<AHasher>>;
+
+#[inline]
+pub fn hash_set_with_capacity<T>(capacity: usize) -> HashSet<T> {
+    HashSet::with_capacity_and_hasher(capacity, BuildHasherDefault::<AHasher>::default())
+}
diff --git a/src/dev/check.rs b/src/dev/check.rs
index 7b172749..ca1b30c9 100644
--- a/src/dev/check.rs
+++ b/src/dev/check.rs
@@ -1,4 +1,3 @@
-use ahash::{HashSet, HashSetExt};
 use anyhow::{anyhow, bail, Context, Error, Result};
 use std::{
     cmp::Ordering,
@@ -12,6 +11,7 @@ use std::{
 use crate::{
     cargo_toml::{append_bins, bins_start_end_ind, BINS_BUFFER_CAPACITY},
     cmd::CmdRunner,
+    collections::{hash_set_with_capacity, HashSet},
     exercise::{RunnableExercise, OUTPUT_CAPACITY},
     info_file::{ExerciseInfo, InfoFile},
     CURRENT_FORMAT_VERSION,
@@ -50,8 +50,8 @@ fn check_cargo_toml(
 
 // Check the info of all exercises and return their paths in a set.
 fn check_info_file_exercises(info_file: &InfoFile) -> Result<HashSet<PathBuf>> {
-    let mut names = HashSet::with_capacity(info_file.exercises.len());
-    let mut paths = HashSet::with_capacity(info_file.exercises.len());
+    let mut names = hash_set_with_capacity(info_file.exercises.len());
+    let mut paths = hash_set_with_capacity(info_file.exercises.len());
 
     let mut file_buf = String::with_capacity(1 << 14);
     for exercise_info in &info_file.exercises {
@@ -251,7 +251,7 @@ fn check_solutions(
             })
             .collect::<Vec<_>>();
 
-        let mut sol_paths = HashSet::with_capacity(info_file.exercises.len());
+        let mut sol_paths = hash_set_with_capacity(info_file.exercises.len());
         let mut fmt_cmd = Command::new("rustfmt");
         fmt_cmd
             .arg("--check")
diff --git a/src/main.rs b/src/main.rs
index edb3e146..58cd8ff6 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -13,6 +13,7 @@ use self::{app_state::AppState, dev::DevCommands, info_file::InfoFile, watch::Wa
 mod app_state;
 mod cargo_toml;
 mod cmd;
+mod collections;
 mod dev;
 mod embedded;
 mod exercise;