Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
fail-fast: false
matrix:
toolchain:
- 1.36.0
- 1.56.0
- stable
features:
# std
Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
name = "anymap3"
version = "1.0.1"
authors = ["Olivier 'reivilibre' (fork maintainer) <contact@librepush.net>", "Chris Morgan (original author) <rust@chrismorgan.info>"]
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"]
Expand Down
1 change: 1 addition & 0 deletions changelog.d/5117772w.removal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Increase Minimum Supported Rust Version (MSRV) to 1.56 (October 2021).
1 change: 1 addition & 0 deletions changelog.d/w5uvz346.misc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix our tests to work with new Rust versions, which changed the internal representation of `TypeId`. Runtime behaviour was unaffected.
2 changes: 1 addition & 1 deletion src/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)) }
}
}

Expand Down
71 changes: 56 additions & 15 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"))]
Expand Down Expand Up @@ -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<T: IntoBox<A>>(&mut self) -> Entry<A, T> {
pub fn entry<T: IntoBox<A>>(&mut self) -> Entry<'_, A, T> {
match self.raw.entry(TypeId::of::<T>()) {
hash_map::Entry::Occupied(e) => Entry::Occupied(OccupiedEntry {
inner: e,
Expand Down Expand Up @@ -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<dyn Any>, Box::new(456), Box::new(true)]);
map.extend([Box::new(123) as Box<dyn Any>, Box::new(456), Box::new(true)]);
assert_eq!(map.get(), Some(&456));
assert_eq!(map.get::<bool>(), Some(&true));
assert!(map.get::<Box<dyn Any>>().is_none());
Expand Down Expand Up @@ -625,9 +622,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]
Expand All @@ -645,12 +643,55 @@ 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::<TypeId, u128>(type_id) } as u64
);

// 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.

if core::mem::size_of::<TypeId>() == core::mem::size_of::<u64>() {
// 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::<TypeId>()
);
}
}
// Pick a variety of types, just to demonstrate it’s all sane. Normal, zero-sized, unsized, &c.
verify_hashing_with(TypeId::of::<usize>());
Expand Down
Loading