From 0bc2911fa103b3414df70ba96830dd67ce718c26 Mon Sep 17 00:00:00 2001 From: Olivier 'reivilibre Date: Sun, 14 Jun 2026 18:03:30 +0100 Subject: [PATCH 1/8] Fix clippy lint Signed-off-by: Olivier 'reivilibre --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 28b9149..41a2284 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -245,7 +245,7 @@ macro_rules! everything { /// Gets the entry for the given type in the collection for in-place manipulation #[inline] - pub fn entry>(&mut self) -> Entry { + pub fn entry>(&mut self) -> Entry<'_, A, T> { match self.raw.entry(TypeId::of::()) { hash_map::Entry::Occupied(e) => Entry::Occupied(OccupiedEntry { inner: e, From 7e323d0697f914a0f680786d8639b7862f9b4408 Mon Sep 17 00:00:00 2001 From: Olivier 'reivilibre Date: Sun, 14 Jun 2026 18:10:26 +0100 Subject: [PATCH 2/8] Reformat TypeIdHasher code to be clearer with if let Signed-off-by: Olivier 'reivilibre --- src/lib.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 41a2284..297d771 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,7 +32,7 @@ #![warn(missing_docs, unused_results)] #![cfg_attr(not(feature = "std"), no_std)] -use core::convert::TryInto; +use core::convert::TryFrom; use core::hash::Hasher; #[cfg(not(feature = "std"))] @@ -625,9 +625,10 @@ impl Hasher for TypeIdHasher { // contract for safety. But I’m OK with release builds putting everything in one bucket // if it *did* change (and debug builds panicking). debug_assert_eq!(bytes.len(), 8); - let _ = bytes - .try_into() - .map(|array| self.value = u64::from_ne_bytes(array)); + + if let Ok(array) = <[u8; 8]>::try_from(bytes) { + self.value = u64::from_ne_bytes(array); + } } #[inline] From 007babf1c08f93a1c4863a403ff5e3f065458439 Mon Sep 17 00:00:00 2001 From: Olivier 'reivilibre Date: Sun, 14 Jun 2026 18:20:29 +0100 Subject: [PATCH 3/8] Bump Rust edition to 2021 and MSRV to 1.56 Signed-off-by: Olivier 'reivilibre --- .github/workflows/ci.yaml | 2 +- Cargo.toml | 4 ++-- src/lib.rs | 5 +---- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index a5b8c47..f05e833 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -12,7 +12,7 @@ jobs: fail-fast: false matrix: toolchain: - - 1.36.0 + - 1.56.0 - stable features: # std diff --git a/Cargo.toml b/Cargo.toml index 178d09f..95283da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,8 +2,8 @@ name = "anymap3" version = "1.0.1" authors = ["Olivier 'reivilibre' (fork maintainer) ", "Chris Morgan (original author) "] -edition = "2018" -rust-version = "1.36" +edition = "2021" +rust-version = "1.56" description = "A safe and convenient store for one value of each type" repository = "https://github.com/reivilibre/anymap3" keywords = ["container", "any", "map"] diff --git a/src/lib.rs b/src/lib.rs index 297d771..3f6eb5b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -573,10 +573,7 @@ macro_rules! everything { #[test] fn test_extend() { let mut map = AnyMap::new(); - // (vec![] for 1.36.0 compatibility; more recently, you should use [] instead.) - #[cfg(not(feature = "std"))] - use alloc::vec; - map.extend(vec![Box::new(123) as Box, Box::new(456), Box::new(true)]); + map.extend([Box::new(123) as Box, Box::new(456), Box::new(true)]); assert_eq!(map.get(), Some(&456)); assert_eq!(map.get::(), Some(&true)); assert!(map.get::>().is_none()); From 4608ec20f39c7d54054a3e6c3cb9410d1877cb42 Mon Sep 17 00:00:00 2001 From: Olivier 'reivilibre Date: Sun, 14 Jun 2026 18:22:00 +0100 Subject: [PATCH 4/8] Fix `type_id_hasher` test to match modern Rust internals The runtime behaviour is still correct; it's only our test assertion that was dodgy Signed-off-by: Olivier 'reivilibre --- src/lib.rs | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3f6eb5b..805421a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -643,11 +643,29 @@ fn type_id_hasher() { fn verify_hashing_with(type_id: TypeId) { let mut hasher = TypeIdHasher::default(); type_id.hash(&mut hasher); - // SAFETY: u128 and u64 are valid for all bit patterns. Transmute checks the sizes match. - // TypeId has a u128 internal value nowadays but only emits the lower 64 bits for its hash. - assert_eq!( - hasher.finish(), - unsafe { core::mem::transmute::(type_id) } as u64 + + // Internally, the TypeId is a 128-bit value and depending on + // Rust version it will provide either the top or bottom 64 bits + // as hash input. + // It's not pretty that we're coupled to this, but at runtime + // the assumption around hash input size is memory-safe + // (with an additional debug assertion). + // This evil transmutation is just about OK for a test. + // It will at least alert us when something changes. + let raw_internal_value: u128 = unsafe { core::mem::transmute::(type_id) }; + + // Bottom bits expected on earlier Rusts + let expected_value_old_rust = raw_internal_value as u64; + // Top bits expected nowadays + let expected_value_new_rust = (raw_internal_value >> 64) as u64; + + let got_value = hasher.finish(); + + assert!( + got_value == expected_value_old_rust || got_value == expected_value_new_rust, + "Hash value from TypeId unexpected. Got {got_value:016x}, + expected either {expected_value_old_rust:016x} (old Rust) + or {expected_value_new_rust:016x} (new Rust)", ); } // Pick a variety of types, just to demonstrate it’s all sane. Normal, zero-sized, unsized, &c. From 346b7f104588e41c76e95241be70099073ad1bda Mon Sep 17 00:00:00 2001 From: Olivier 'reivilibre Date: Sun, 14 Jun 2026 18:24:38 +0100 Subject: [PATCH 5/8] Changelog fragments Signed-off-by: Olivier 'reivilibre --- changelog.d/5117772w.removal.md | 1 + changelog.d/w5uvz346.misc.md | 1 + 2 files changed, 2 insertions(+) create mode 100644 changelog.d/5117772w.removal.md create mode 100644 changelog.d/w5uvz346.misc.md diff --git a/changelog.d/5117772w.removal.md b/changelog.d/5117772w.removal.md new file mode 100644 index 0000000..eb6f4ff --- /dev/null +++ b/changelog.d/5117772w.removal.md @@ -0,0 +1 @@ +Increase Minimum Supported Rust Version (MSRV) to 1.56 (October 2021). diff --git a/changelog.d/w5uvz346.misc.md b/changelog.d/w5uvz346.misc.md new file mode 100644 index 0000000..ddfd640 --- /dev/null +++ b/changelog.d/w5uvz346.misc.md @@ -0,0 +1 @@ +Fix our tests to work with new Rust versions, which changed the internal representation of `TypeId`. Runtime behaviour was unaffected. From e1af54c456551dbef33aad5f5064750f53908ed6 Mon Sep 17 00:00:00 2001 From: Olivier 'reivilibre Date: Sun, 14 Jun 2026 18:28:56 +0100 Subject: [PATCH 6/8] Fix use of `std` instead of `core` Signed-off-by: Olivier 'reivilibre --- src/any.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/any.rs b/src/any.rs index e3db751..2f45fb5 100644 --- a/src/any.rs +++ b/src/any.rs @@ -59,7 +59,7 @@ macro_rules! impl_clone { // described in [1], that is the recommended way to suppress the warning. // // [1]: https://github.com/rust-lang/rust/issues/127323 - unsafe { Box::from_raw(std::mem::transmute::<*mut dyn CloneAny, *mut _>(raw)) } + unsafe { Box::from_raw(core::mem::transmute::<*mut dyn CloneAny, *mut _>(raw)) } } } From 992921d080b7309187c87419f94efdda5b1019aa Mon Sep 17 00:00:00 2001 From: Olivier 'reivilibre Date: Sun, 14 Jun 2026 18:33:41 +0100 Subject: [PATCH 7/8] Placeholders still not properly supported on 1.56 after all :( Signed-off-by: Olivier 'reivilibre --- src/lib.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 805421a..4af5961 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -663,9 +663,12 @@ fn type_id_hasher() { assert!( got_value == expected_value_old_rust || got_value == expected_value_new_rust, - "Hash value from TypeId unexpected. Got {got_value:016x}, - expected either {expected_value_old_rust:016x} (old Rust) - or {expected_value_new_rust:016x} (new Rust)", + "Hash value from TypeId unexpected. Got {:016x}, + expected either {:016x} (old Rust) + or {:016x} (new Rust)", + got_value, + expected_value_old_rust, + expected_value_new_rust, ); } // Pick a variety of types, just to demonstrate it’s all sane. Normal, zero-sized, unsized, &c. From 94217bee9bdf4546f992c72044d79a1180946059 Mon Sep 17 00:00:00 2001 From: Olivier 'reivilibre Date: Sun, 14 Jun 2026 18:46:49 +0100 Subject: [PATCH 8/8] Expand more cases on the type_id_hasher test Signed-off-by: Olivier 'reivilibre --- src/lib.rs | 64 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 4af5961..9512676 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -644,32 +644,54 @@ fn type_id_hasher() { let mut hasher = TypeIdHasher::default(); type_id.hash(&mut hasher); - // Internally, the TypeId is a 128-bit value and depending on - // Rust version it will provide either the top or bottom 64 bits - // as hash input. + // Internally, the TypeId is (depending on Rust version) + // either a 64-bit or 128-bit value. + // Depending on Rust version it will provide either the top + // or bottom 64 bits as hash input. // It's not pretty that we're coupled to this, but at runtime // the assumption around hash input size is memory-safe // (with an additional debug assertion). // This evil transmutation is just about OK for a test. // It will at least alert us when something changes. - let raw_internal_value: u128 = unsafe { core::mem::transmute::(type_id) }; - - // Bottom bits expected on earlier Rusts - let expected_value_old_rust = raw_internal_value as u64; - // Top bits expected nowadays - let expected_value_new_rust = (raw_internal_value >> 64) as u64; - - let got_value = hasher.finish(); - - assert!( - got_value == expected_value_old_rust || got_value == expected_value_new_rust, - "Hash value from TypeId unexpected. Got {:016x}, - expected either {:016x} (old Rust) - or {:016x} (new Rust)", - got_value, - expected_value_old_rust, - expected_value_new_rust, - ); + + if core::mem::size_of::() == core::mem::size_of::() { + // Old Rust only + let expected_value_old_rust: u64 = + *unsafe { core::mem::transmute::<&TypeId, &u64>(&type_id) }; + + let got_value = hasher.finish(); + + assert!( + got_value == expected_value_old_rust, + "Hash value from TypeId unexpected. Got {:016x}, + expected {:016x} [using TypeId of size u64]", + got_value, + expected_value_old_rust, + ); + } else { + // On newer Rusts, the internal state is currently u128 + let raw_internal_value: &[u64; 2] = + unsafe { core::mem::transmute::<&TypeId, &[u64; 2]>(&type_id) }; + + // Even at u128 size, the expected value seems to + // depend on version of Rust + // (Going by the history of this test code) + let expected_value_old_rust = raw_internal_value[0] as u64; + let expected_value_new_rust = raw_internal_value[1] as u64; + + let got_value = hasher.finish(); + + assert!( + got_value == expected_value_old_rust || got_value == expected_value_new_rust, + "Hash value from TypeId unexpected. Got {:016x}, + expected either {:016x} (oldish Rust) + or {:016x} (newish Rust) [using TypeId of size {}]", + got_value, + expected_value_old_rust, + expected_value_new_rust, + core::mem::size_of::() + ); + } } // Pick a variety of types, just to demonstrate it’s all sane. Normal, zero-sized, unsized, &c. verify_hashing_with(TypeId::of::());