Skip to content

Commit 0e68f8a

Browse files
authored
Merge pull request #422 from cuviper/msrv-1.82
Release 2.12.0
2 parents 86c319b + 61c9c94 commit 0e68f8a

File tree

18 files changed

+87
-147
lines changed

18 files changed

+87
-147
lines changed

.github/workflows/ci.yml

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
strategy:
1818
matrix:
1919
include:
20-
- rust: 1.63.0 # MSRV
20+
- rust: 1.82.0 # MSRV
2121
features:
2222
- rust: stable
2323
features: arbitrary
@@ -40,13 +40,8 @@ jobs:
4040

4141
steps:
4242
- uses: actions/checkout@v4
43-
- uses: actions/cache@v4
44-
if: matrix.rust == '1.63.0'
45-
with:
46-
path: ~/.cargo/registry/index
47-
key: cargo-git-index
4843
- name: Lock MSRV-compatible dependencies
49-
if: matrix.rust == '1.63.0'
44+
if: matrix.rust == '1.82.0'
5045
env:
5146
CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS: fallback
5247
# Note that this uses the runner's pre-installed stable cargo
@@ -77,20 +72,15 @@ jobs:
7772
strategy:
7873
matrix:
7974
include:
80-
- rust: 1.63.0
75+
- rust: 1.82.0
8176
target: thumbv6m-none-eabi
8277
- rust: stable
8378
target: thumbv6m-none-eabi
8479

8580
steps:
8681
- uses: actions/checkout@v4
87-
- uses: actions/cache@v4
88-
if: matrix.rust == '1.63.0'
89-
with:
90-
path: ~/.cargo/registry/index
91-
key: cargo-git-index
9282
- name: Lock MSRV-compatible dependencies
93-
if: matrix.rust == '1.63.0'
83+
if: matrix.rust == '1.82.0'
9484
env:
9585
CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS: fallback
9686
# Note that this uses the runner's pre-installed stable cargo
@@ -123,20 +113,18 @@ jobs:
123113
- uses: taiki-e/install-action@v2
124114
with:
125115
tool: cargo-nextest
116+
if: github.event_name == 'merge_group'
126117
- run: cargo miri nextest run
118+
if: github.event_name == 'merge_group'
127119
- run: cargo miri test --doc
128120

129121
minimal-versions:
130122
name: Check MSRV and minimal-versions
131123
runs-on: ubuntu-latest
132124
steps:
133125
- uses: actions/checkout@v4
134-
- uses: actions/cache@v4
135-
with:
136-
path: ~/.cargo/registry/index
137-
key: cargo-git-index
138126
- uses: dtolnay/rust-toolchain@nightly
139-
- uses: dtolnay/rust-toolchain@1.63.0 # MSRV
127+
- uses: dtolnay/rust-toolchain@1.82.0 # MSRV
140128
- uses: taiki-e/install-action@v2
141129
with:
142130
tool: cargo-hack

Cargo.toml

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
[package]
22
name = "indexmap"
33
edition = "2021"
4-
version = "2.11.4"
4+
version = "2.12.0"
55
documentation = "https://docs.rs/indexmap/"
66
repository = "https://github.com/indexmap-rs/indexmap"
77
license = "Apache-2.0 OR MIT"
88
description = "A hash table with consistent order and fast iteration."
99
keywords = ["hashmap", "no_std"]
1010
categories = ["data-structures", "no-std"]
11-
rust-version = "1.63"
11+
rust-version = "1.82"
1212

1313
[lib]
1414
bench = false
1515

1616
[dependencies]
1717
equivalent = { version = "1.0", default-features = false }
18+
hashbrown = { version = "0.16", default-features = false }
1819

1920
arbitrary = { version = "1.0", optional = true, default-features = false }
2021
quickcheck = { version = "1.0", optional = true, default-features = false }
@@ -25,10 +26,6 @@ sval = { version = "2", optional = true, default-features = false }
2526
# deprecated: use borsh's "indexmap" feature instead.
2627
borsh = { version = "1.2", optional = true, default-features = false }
2728

28-
[dependencies.hashbrown]
29-
version = ">= 0.15.0, < 0.17.0"
30-
default-features = false
31-
3229
# serde v1.0.220 is the first version that released with `serde_core`.
3330
# This is required to avoid conflict with other `serde` users which may require an older version.
3431
[target.'cfg(any())'.dependencies]
@@ -64,5 +61,16 @@ rustdoc-args = ["--cfg", "docsrs"]
6461
[workspace]
6562
members = ["test-nostd", "test-serde", "test-sval"]
6663

64+
[lints.rust]
65+
private-bounds = "deny"
66+
private-interfaces = "deny"
67+
unnameable-types = "deny"
68+
unreachable-pub = "deny"
69+
70+
# We *mostly* avoid unsafe code, but there are a few fine-grained cases allowed
71+
unsafe-code = "deny"
72+
73+
rust-2018-idioms = "warn"
74+
6775
[lints.clippy]
6876
style = "allow"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[![build status](https://github.com/indexmap-rs/indexmap/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/indexmap-rs/indexmap/actions)
44
[![crates.io](https://img.shields.io/crates/v/indexmap.svg)](https://crates.io/crates/indexmap)
55
[![docs](https://docs.rs/indexmap/badge.svg)](https://docs.rs/indexmap)
6-
[![rustc](https://img.shields.io/badge/rust-1.63%2B-orange.svg)](https://img.shields.io/badge/rust-1.63%2B-orange.svg)
6+
[![rustc](https://img.shields.io/badge/rust-1.82%2B-orange.svg)](https://img.shields.io/badge/rust-1.82%2B-orange.svg)
77

88
A pure-Rust hash table which preserves (in a limited sense) insertion order.
99

RELEASES.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Releases
22

3+
## 2.12.0 (2025-10-17)
4+
5+
- **MSRV**: Rust 1.82.0 or later is now required.
6+
- Updated the `hashbrown` dependency to 0.16 alone.
7+
- Error types now implement `core::error::Error`.
8+
- Added `pop_if` methods to `IndexMap` and `IndexSet`, similar to the
9+
method for `Vec` added in Rust 1.86.
10+
311
## 2.11.4 (2025-09-18)
412

513
- Updated the `hashbrown` dependency to a range allowing 0.15 or 0.16.

benches/bench.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ extern crate test;
55
use fnv::FnvHasher;
66
use std::hash::BuildHasherDefault;
77
use std::hash::Hash;
8+
use std::hint::black_box;
89
use std::sync::LazyLock;
910
type FnvBuilder = BuildHasherDefault<FnvHasher>;
1011

11-
use test::black_box;
1212
use test::Bencher;
1313

1414
use indexmap::IndexMap;

benches/faststring.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@ impl<'a, S> From<&'a S> for &'a OneShot<str>
3333
where
3434
S: AsRef<str>,
3535
{
36+
#[allow(unsafe_code)]
3637
fn from(s: &'a S) -> Self {
3738
let s: &str = s.as_ref();
39+
// SAFETY: OneShot is a `repr(transparent)` wrapper
3840
unsafe { &*(s as *const str as *const OneShot<str>) }
3941
}
4042
}

src/borsh.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
use alloc::vec::Vec;
44
use core::hash::BuildHasher;
55
use core::hash::Hash;
6-
use core::mem::size_of;
76

87
use borsh::error::ERROR_ZST_FORBIDDEN;
98
use borsh::io::{Error, ErrorKind, Read, Result, Write};

src/lib.rs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
// We *mostly* avoid unsafe code, but `Slice` allows it for DST casting.
2-
#![deny(unsafe_code)]
3-
#![warn(rust_2018_idioms)]
41
#![no_std]
52

63
//! [`IndexMap`] is a hash table where the iteration order of the key-value
@@ -60,7 +57,7 @@
6057
//! ### Alternate Hashers
6158
//!
6259
//! [`IndexMap`] and [`IndexSet`] have a default hasher type
63-
//! [`S = RandomState`][std::collections::hash_map::RandomState],
60+
//! [`S = RandomState`][std::hash::RandomState],
6461
//! just like the standard `HashMap` and `HashSet`, which is resistant to
6562
//! HashDoS attacks but not the most performant. Type aliases can make it easier
6663
//! to use alternate hashers:
@@ -79,7 +76,7 @@
7976
//!
8077
//! ### Rust Version
8178
//!
82-
//! This version of indexmap requires Rust 1.63 or later.
79+
//! This version of indexmap requires Rust 1.82 or later.
8380
//!
8481
//! The indexmap 2.x release series will use a carefully considered version
8582
//! upgrade policy, where in a later 2.x version, we will raise the minimum
@@ -255,9 +252,7 @@ impl core::fmt::Display for TryReserveError {
255252
}
256253
}
257254

258-
#[cfg(feature = "std")]
259-
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
260-
impl std::error::Error for TryReserveError {}
255+
impl core::error::Error for TryReserveError {}
261256

262257
// NOTE: This is copied from the slice module in the std lib.
263258
/// The error type returned by [`get_disjoint_indices_mut`][`IndexMap::get_disjoint_indices_mut`].
@@ -285,6 +280,4 @@ impl core::fmt::Display for GetDisjointMutError {
285280
}
286281
}
287282

288-
#[cfg(feature = "std")]
289-
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
290-
impl std::error::Error for GetDisjointMutError {}
283+
impl core::error::Error for GetDisjointMutError {}

src/map.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@ pub use crate::rayon::map as rayon;
2828

2929
use ::core::cmp::Ordering;
3030
use ::core::fmt;
31-
use ::core::hash::{BuildHasher, Hash, Hasher};
31+
use ::core::hash::{BuildHasher, Hash};
3232
use ::core::mem;
3333
use ::core::ops::{Index, IndexMut, RangeBounds};
3434
use alloc::boxed::Box;
3535
use alloc::vec::Vec;
3636

3737
#[cfg(feature = "std")]
38-
use std::collections::hash_map::RandomState;
38+
use std::hash::RandomState;
3939

4040
pub(crate) use self::core::{ExtractCore, IndexMapCore};
4141
use crate::util::{third, try_simplify_range};
@@ -813,9 +813,8 @@ where
813813
S: BuildHasher,
814814
{
815815
pub(crate) fn hash<Q: ?Sized + Hash>(&self, key: &Q) -> HashValue {
816-
let mut h = self.hash_builder.build_hasher();
817-
key.hash(&mut h);
818-
HashValue(h.finish() as usize)
816+
let h = self.hash_builder.hash_one(key);
817+
HashValue(h as usize)
819818
}
820819

821820
/// Return `true` if an equivalent to `key` exists in the map.
@@ -1826,10 +1825,11 @@ where
18261825
// Otherwise reserve half the hint (rounded up), so the map
18271826
// will only resize twice in the worst case.
18281827
let iter = iterable.into_iter();
1828+
let (lower_len, _) = iter.size_hint();
18291829
let reserve = if self.is_empty() {
1830-
iter.size_hint().0
1830+
lower_len
18311831
} else {
1832-
(iter.size_hint().0 + 1) / 2
1832+
lower_len.div_ceil(2)
18331833
};
18341834
self.reserve(reserve);
18351835
iter.for_each(move |(k, v)| {

src/map/core.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,15 @@ struct RefMut<'a, K, V> {
4747
}
4848

4949
#[inline(always)]
50-
fn get_hash<K, V>(entries: &[Bucket<K, V>]) -> impl Fn(&usize) -> u64 + '_ {
50+
fn get_hash<K, V>(entries: &[Bucket<K, V>]) -> impl Fn(&usize) -> u64 + use<'_, K, V> {
5151
move |&i| entries[i].hash.get()
5252
}
5353

5454
#[inline]
5555
fn equivalent<'a, K, V, Q: ?Sized + Equivalent<K>>(
5656
key: &'a Q,
5757
entries: &'a [Bucket<K, V>],
58-
) -> impl Fn(&usize) -> bool + 'a {
58+
) -> impl Fn(&usize) -> bool + use<'a, K, V, Q> {
5959
move |&i| Q::equivalent(key, &entries[i].key)
6060
}
6161

@@ -111,7 +111,7 @@ where
111111

112112
impl<K, V> IndexMapCore<K, V> {
113113
/// The maximum capacity before the `entries` allocation would exceed `isize::MAX`.
114-
const MAX_ENTRIES_CAPACITY: usize = (isize::MAX as usize) / mem::size_of::<Bucket<K, V>>();
114+
const MAX_ENTRIES_CAPACITY: usize = (isize::MAX as usize) / size_of::<Bucket<K, V>>();
115115

116116
#[inline]
117117
pub(crate) const fn new() -> Self {

0 commit comments

Comments
 (0)