From 4e49926c34f1dbb9757087be4eead7459bab088b Mon Sep 17 00:00:00 2001 From: Mateusz Kowalczyk Date: Mon, 18 Oct 2021 12:10:49 +0900 Subject: [PATCH] Stable ordering when generating StructMeta code Currently, when user specifies `derive(StructMeta)`, this crate generates a branch of code for each of the attributes. These attributes however have so far been stored inside a `HashMap` which means the ordering of the branches is more or less random. This has no real impact on the runtime: the order of the branches doesn't change the semantics of the code. It does matter however for compile time: `rustc` will calculate a different crate hash (effectively a sort of ABI signature) if code is re-ordered. This means that any time we recompile code with `derive(StructMeta)` somewhere, we're breaking the ABI even if there were _no_ changes at all to any code. Basically, we're throwing a dice at compile time as to what order the code will be laid out in. This is very bad for reproducability and plays very poorly with any sort of binary caching. I initially thought that the reproducability issue was coming from `rustc` itself but the more I was debugging, I made my way back to this crate. You can see the original rustc issue for context [here](https://github.com/rust-lang/rust/issues/89904). I think this change should be basically invisible to anyone that's been using the crate so far. --- structmeta-derive/src/struct_meta.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/structmeta-derive/src/struct_meta.rs b/structmeta-derive/src/struct_meta.rs index 649c93b..72c146f 100644 --- a/structmeta-derive/src/struct_meta.rs +++ b/structmeta-derive/src/struct_meta.rs @@ -1,7 +1,7 @@ use crate::syn_utils::*; use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote, quote_spanned}; -use std::collections::HashMap; +use std::collections::BTreeMap; use syn::{ ext::IdentExt, parse::{Parse, ParseStream}, @@ -52,7 +52,7 @@ struct Params<'a> { unnamed_required: Vec>, unnamed_optional: Vec>, unnamed_variadic: Option>, - named: HashMap>, + named: BTreeMap>, rest: Option>, } impl<'a> Params<'a> { @@ -60,7 +60,7 @@ impl<'a> Params<'a> { let mut unnamed_required = Vec::new(); let mut unnamed_optional = Vec::new(); let mut unnamed_variadic = None; - let mut named = HashMap::new(); + let mut named = BTreeMap::new(); let mut rest = None; for (index, field) in fields.iter().enumerate() { let span = field.span();