Repository: osa1/tiny (language: rust)

Issue:
reproducible builds problem
While working on [reproducible builds](https://reproducible-builds.org/) for [openSUSE](https://en.opensuse.org/openSUSE:Reproducible_Builds) (sponsored by the NLnet NGI0 fund), I found that
our `tiny` package varies in every build.

Another developer pointed at HashMaps in
https://github.com/osa1/tiny/blob/ee8615a55256b242b02e6f8a2350ca7f39aca517/crates/term_input_macros/src/tree.rs#L6
with non-deterministic iteration order.

Maybe it could be replaced with [indexmap](https://github.com/indexmap-rs/indexmap), [ordermap](https://github.com/indexmap-rs/ordermap) or something else...


Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ab1b2e1e..13936c08 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,8 @@
 - Improve nick matching to avoid highlighting message incorrectly. (#430)
 - Fix resetting message color when a color prefix (0x03) is not followed by a
   color code. (#434)
+- Refactor an internal macro to make tiny builds deterministic, allowing
+  reproducible builds. (#437)
 
 # 2024/01/01: 0.12.0
 
diff --git a/Cargo.lock b/Cargo.lock
index 8e03c6c1..d948d117 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,6 +1,6 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
-version = 3
+version = 4
 
 [[package]]
 name = "addr2line"
@@ -172,6 +172,12 @@ dependencies = [
  "log",
 ]
 
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
 [[package]]
 name = "errno"
 version = "0.3.4"
@@ -261,6 +267,12 @@ version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
 
+[[package]]
+name = "hashbrown"
+version = "0.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
+
 [[package]]
 name = "indexmap"
 version = "1.9.3"
@@ -268,7 +280,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
 dependencies = [
  "autocfg",
- "hashbrown",
+ "hashbrown 0.12.3",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.15.2",
 ]
 
 [[package]]
@@ -808,7 +830,7 @@ version = "0.8.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b"
 dependencies = [
- "indexmap",
+ "indexmap 1.9.3",
  "ryu",
  "serde",
  "yaml-rust",
@@ -897,6 +919,7 @@ dependencies = [
 name = "term_input_macros"
 version = "0.2.0"
 dependencies = [
+ "indexmap 2.7.0",
  "proc-macro2",
  "quote",
  "syn",
diff --git a/crates/term_input_macros/Cargo.toml b/crates/term_input_macros/Cargo.toml
index 131d0888..f449f837 100644
--- a/crates/term_input_macros/Cargo.toml
+++ b/crates/term_input_macros/Cargo.toml
@@ -8,6 +8,7 @@ edition = "2021"
 proc-macro = true
 
 [dependencies]
+indexmap = "2.7.0"
 proc-macro2 = "1.0"
 quote = "1.0"
 syn = { version = "2.0", features = ["full", "extra-traits"] }
diff --git a/crates/term_input_macros/src/tree.rs b/crates/term_input_macros/src/tree.rs
index c4a3b50a..5096988f 100644
--- a/crates/term_input_macros/src/tree.rs
+++ b/crates/term_input_macros/src/tree.rs
@@ -1,14 +1,17 @@
 use crate::syntax::*;
 
+use indexmap::map::IndexMap;
 use proc_macro2::TokenStream;
 use quote::quote;
 use quote::TokenStreamExt;
-use std::collections::HashMap;
 
 struct Node {
     idx: usize,
     value: Option<syn::Expr>,
-    next: HashMap<u8, Node>,
+
+    // Note: `IndexMap` to be able to deterministically iterate the map and generate code
+    // deterministically, which allows reproducible builds.
+    next: IndexMap<u8, Node>,
 }
 
 impl Node {
@@ -16,7 +19,7 @@ impl Node {
         Node {
             idx,
             value: None,
-            next: HashMap::new(),
+            next: IndexMap::new(),
         }
     }
 


Test patch: