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
20 changes: 3 additions & 17 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
strategy:
matrix:
include:
- rust: 1.82.0 # MSRV
- rust: 1.85.0 # MSRV
features:
- rust: stable
features: arbitrary
Expand All @@ -40,12 +40,6 @@ jobs:

steps:
- uses: actions/checkout@v4
- name: Lock MSRV-compatible dependencies
if: matrix.rust == '1.82.0'
env:
CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS: fallback
# Note that this uses the runner's pre-installed stable cargo
run: cargo generate-lockfile
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
Expand All @@ -72,19 +66,13 @@ jobs:
strategy:
matrix:
include:
- rust: 1.82.0
- rust: 1.85.0
target: thumbv6m-none-eabi
- rust: stable
target: thumbv6m-none-eabi

steps:
- uses: actions/checkout@v4
- name: Lock MSRV-compatible dependencies
if: matrix.rust == '1.82.0'
env:
CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS: fallback
# Note that this uses the runner's pre-installed stable cargo
run: cargo generate-lockfile
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
Expand Down Expand Up @@ -124,14 +112,12 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
- uses: dtolnay/rust-toolchain@1.82.0 # MSRV
- uses: dtolnay/rust-toolchain@1.85.0 # MSRV
- uses: taiki-e/install-action@v2
with:
tool: cargo-hack
- name: Lock minimal direct dependencies
run: cargo +nightly hack generate-lockfile --remove-dev-deps -Z direct-minimal-versions
env:
CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS: fallback
- name: Build (nightly)
run: cargo +nightly build --verbose --all-features
- name: Build (MSRV)
Expand Down
2 changes: 1 addition & 1 deletion .rustfmt.toml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
edition = "2021"
edition = "2024"
10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
[package]
name = "ringmap"
edition = "2021"
version = "0.2.4"
edition = "2024"
version = "0.2.5"
documentation = "https://docs.rs/ringmap/"
repository = "https://github.com/indexmap-rs/ringmap"
license = "Apache-2.0 OR MIT"
description = "A hash table with consistent deque-like order and fast iteration."
keywords = ["hashmap", "no_std"]
categories = ["data-structures", "no-std"]
rust-version = "1.82"
rust-version = "1.85"

[lib]
bench = false

[dependencies]
equivalent = { version = "1.0", default-features = false }
hashbrown = { version = "0.16.1", default-features = false }
hashbrown = { version = "0.17", default-features = false }

arbitrary = { version = "1.0", optional = true, default-features = false }
quickcheck = { version = "1.0", optional = true, default-features = false }
Expand All @@ -32,7 +32,7 @@ serde = { version = "1.0.220", default-features = false, optional = true }
[dev-dependencies]
itertools = "0.14"
fastrand = { version = "2", default-features = false }
quickcheck = { version = "1.0", default-features = false }
quickcheck = { version = "1.1", default-features = false }
fnv = "1.0"
serde = { version = "1.0", default-features = false, features = ["derive"] }

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![build status](https://github.com/indexmap-rs/ringmap/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/indexmap-rs/ringmap/actions)
[![crates.io](https://img.shields.io/crates/v/ringmap.svg)](https://crates.io/crates/ringmap)
[![docs](https://docs.rs/ringmap/badge.svg)](https://docs.rs/ringmap)
[![rustc](https://img.shields.io/badge/rust-1.82%2B-orange.svg)](https://img.shields.io/badge/rust-1.82%2B-orange.svg)
[![rustc](https://img.shields.io/badge/rust-1.85%2B-orange.svg)](https://img.shields.io/badge/rust-1.85%2B-orange.svg)

A pure-Rust hash table which preserves (in a limited sense) insertion order,
with efficient deque-like manipulation of both the front and back ends.
Expand Down
7 changes: 7 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Releases

## 0.2.5 (2026-04-09)

- **MSRV**: Rust 1.85.0 or later is now required.
- Updated the `hashbrown` dependency to 0.17.
- Made more `map::Slice` methods `const`: `new_mut`, `first_mut`, `last_mut`,
`split_at_mut`, `split_at_mut_checked`, `split_first_mut`, `split_last_mut`

## 0.2.4 (2026-04-02)

- Made some `Slice` methods `const`:
Expand Down
4 changes: 2 additions & 2 deletions src/inner/entry.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::{equivalent, get_hash, Bucket, Core, OffsetIndex};
use crate::map::{Entry, IndexedEntry};
use super::{Bucket, Core, OffsetIndex, equivalent, get_hash};
use crate::HashValue;
use crate::map::{Entry, IndexedEntry};
use core::cmp::Ordering;
use core::mem;

Expand Down
8 changes: 4 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
//!
//! ### Rust Version
//!
//! This version of ringmap requires Rust 1.82 or later.
//! This version of ringmap requires Rust 1.85 or later.
//!
//! The ringmap 0.2 release series will use a carefully considered version
//! upgrade policy, where in a later 0.x version, we will raise the minimum
Expand Down Expand Up @@ -176,7 +176,7 @@ impl<K, V> Bucket<K, V> {
const fn value_ref(&self) -> &V {
&self.value
}
fn value_mut(&mut self) -> &mut V {
const fn value_mut(&mut self) -> &mut V {
&mut self.value
}
fn key(self) -> K {
Expand All @@ -191,10 +191,10 @@ impl<K, V> Bucket<K, V> {
const fn refs(&self) -> (&K, &V) {
(&self.key, &self.value)
}
fn ref_mut(&mut self) -> (&K, &mut V) {
const fn ref_mut(&mut self) -> (&K, &mut V) {
(&self.key, &mut self.value)
}
fn muts(&mut self) -> (&mut K, &mut V) {
const fn muts(&mut self) -> (&mut K, &mut V) {
(&mut self.key, &mut self.value)
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
macro_rules! ringmap_with_default {
($H:ty; $($key:expr => $value:expr,)+) => { $crate::ringmap_with_default!($H; $($key => $value),+) };
($H:ty; $($key:expr => $value:expr),*) => {{
let builder = ::core::hash::BuildHasherDefault::<$H>::default();
let builder = ::core::hash::BuildHasherDefault::<$H>::new();
const CAP: usize = <[()]>::len(&[$({ stringify!($key); }),*]);
#[allow(unused_mut)]
// Specify your custom `H` (must implement Default + Hasher) as the hasher:
Expand Down Expand Up @@ -97,7 +97,7 @@ macro_rules! ringmap {
macro_rules! ringset_with_default {
($H:ty; $($value:expr,)+) => { $crate::ringset_with_default!($H; $($value),+) };
($H:ty; $($value:expr),*) => {{
let builder = ::core::hash::BuildHasherDefault::<$H>::default();
let builder = ::core::hash::BuildHasherDefault::<$H>::new();
const CAP: usize = <[()]>::len(&[$({ stringify!($value); }),*]);
#[allow(unused_mut)]
// Specify your custom `H` (must implement Default + Hash) as the hasher:
Expand Down
5 changes: 4 additions & 1 deletion src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -968,14 +968,17 @@ where
}
}

/// Return the values for `N` keys. If any key is duplicated, this function will panic.
/// Return the values for `N` keys.
///
/// ***Panics*** if any key is duplicated.
///
/// # Examples
///
/// ```
/// let mut map = ringmap::RingMap::from([(1, 'a'), (3, 'b'), (2, 'c')]);
/// assert_eq!(map.get_disjoint_mut([&2, &1]), [Some(&mut 'c'), Some(&mut 'a')]);
/// ```
#[track_caller]
pub fn get_disjoint_mut<Q, const N: usize>(&mut self, keys: [&Q; N]) -> [Option<&mut V>; N]
where
Q: ?Sized + Hash + Equivalent<K>,
Expand Down
2 changes: 1 addition & 1 deletion src/map/serde_seq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ use core::fmt::{self, Formatter};
use core::hash::{BuildHasher, Hash};
use core::marker::PhantomData;

use crate::RingMap;
use crate::map::Slice as MapSlice;
use crate::serde::cautious_capacity;
use crate::set::Slice as SetSlice;
use crate::RingMap;

/// Serializes a [`map::Slice`][MapSlice] as an ordered sequence.
///
Expand Down
37 changes: 24 additions & 13 deletions src/map/slice.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::{Bucket, IntoIter, IntoKeys, IntoValues, Iter, IterMut, Keys, Values, ValuesMut};
use crate::util::{slice_eq, try_simplify_range};
use crate::GetDisjointMutError;
use crate::util::{slice_eq, try_simplify_range};

use alloc::boxed::Box;
use alloc::collections::VecDeque;
Expand All @@ -26,7 +26,7 @@ impl<K, V> Slice<K, V> {
unsafe { &*(entries as *const [Bucket<K, V>] as *const Self) }
}

pub(super) fn from_mut_slice(entries: &mut [Bucket<K, V>]) -> &mut Self {
pub(super) const fn from_mut_slice(entries: &mut [Bucket<K, V>]) -> &mut Self {
unsafe { &mut *(entries as *mut [Bucket<K, V>] as *mut Self) }
}

Expand All @@ -50,7 +50,7 @@ impl<K, V> Slice<K, V> {
}

/// Returns an empty mutable slice.
pub fn new_mut<'a>() -> &'a mut Self {
pub const fn new_mut<'a>() -> &'a mut Self {
Self::from_mut_slice(&mut [])
}

Expand Down Expand Up @@ -106,8 +106,12 @@ impl<K, V> Slice<K, V> {
}

/// Get the first key-value pair, with mutable access to the value.
pub fn first_mut(&mut self) -> Option<(&K, &mut V)> {
self.entries.first_mut().map(Bucket::ref_mut)
pub const fn first_mut(&mut self) -> Option<(&K, &mut V)> {
if let [first, ..] = &mut self.entries {
Some(first.ref_mut())
} else {
None
}
}

/// Get the last key-value pair.
Expand All @@ -120,8 +124,12 @@ impl<K, V> Slice<K, V> {
}

/// Get the last key-value pair, with mutable access to the value.
pub fn last_mut(&mut self) -> Option<(&K, &mut V)> {
self.entries.last_mut().map(Bucket::ref_mut)
pub const fn last_mut(&mut self) -> Option<(&K, &mut V)> {
if let [.., last] = &mut self.entries {
Some(last.ref_mut())
} else {
None
}
}

/// Divides one slice into two at an index.
Expand All @@ -139,7 +147,7 @@ impl<K, V> Slice<K, V> {
/// ***Panics*** if `index > len`.
/// For a non-panicking alternative see [`split_at_mut_checked`][Self::split_at_mut_checked].
#[track_caller]
pub fn split_at_mut(&mut self, index: usize) -> (&mut Self, &mut Self) {
pub const fn split_at_mut(&mut self, index: usize) -> (&mut Self, &mut Self) {
let (first, second) = self.entries.split_at_mut(index);
(Self::from_mut_slice(first), Self::from_mut_slice(second))
}
Expand All @@ -158,9 +166,12 @@ impl<K, V> Slice<K, V> {
/// Divides one mutable slice into two at an index.
///
/// Returns `None` if `index > len`.
pub fn split_at_mut_checked(&mut self, index: usize) -> Option<(&mut Self, &mut Self)> {
let (first, second) = self.entries.split_at_mut_checked(index)?;
Some((Self::from_mut_slice(first), Self::from_mut_slice(second)))
pub const fn split_at_mut_checked(&mut self, index: usize) -> Option<(&mut Self, &mut Self)> {
if let Some((first, second)) = self.entries.split_at_mut_checked(index) {
Some((Self::from_mut_slice(first), Self::from_mut_slice(second)))
} else {
None
}
}

/// Returns the first key-value pair and the rest of the slice,
Expand All @@ -175,7 +186,7 @@ impl<K, V> Slice<K, V> {

/// Returns the first key-value pair and the rest of the slice,
/// with mutable access to the value, or `None` if it is empty.
pub fn split_first_mut(&mut self) -> Option<((&K, &mut V), &mut Self)> {
pub const fn split_first_mut(&mut self) -> Option<((&K, &mut V), &mut Self)> {
if let [first, rest @ ..] = &mut self.entries {
Some((first.ref_mut(), Self::from_mut_slice(rest)))
} else {
Expand All @@ -195,7 +206,7 @@ impl<K, V> Slice<K, V> {

/// Returns the last key-value pair and the rest of the slice,
/// with mutable access to the value, or `None` if it is empty.
pub fn split_last_mut(&mut self) -> Option<((&K, &mut V), &mut Self)> {
pub const fn split_last_mut(&mut self) -> Option<((&K, &mut V), &mut Self)> {
if let [rest @ .., last] = &mut self.entries {
Some((last.ref_mut(), Self::from_mut_slice(rest)))
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/rayon/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ use core::fmt;
use core::hash::{BuildHasher, Hash};
use core::ops::RangeBounds;

use crate::map::Slice;
use crate::Bucket;
use crate::RingMap;
use crate::map::Slice;

impl<K, V, S> IntoParallelIterator for RingMap<K, V, S>
where
Expand Down
2 changes: 1 addition & 1 deletion src/rayon/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ use core::fmt;
use core::hash::{BuildHasher, Hash};
use core::ops::RangeBounds;

use crate::set::Slice;
use crate::RingSet;
use crate::set::Slice;

type Bucket<T> = crate::Bucket<T, ()>;

Expand Down
2 changes: 1 addition & 1 deletion src/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ pub use self::iter::{
pub use self::mutable::MutableValues;
pub use self::slice::Slice;

use crate::TryReserveError;
#[cfg(feature = "rayon")]
pub use crate::rayon::set as rayon;
use crate::TryReserveError;

#[cfg(feature = "std")]
use std::hash::RandomState;
Expand Down
2 changes: 1 addition & 1 deletion src/set/iter.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::inner::extract::ExtractCore;
use crate::inner::Core;
use crate::inner::extract::ExtractCore;

use super::{Bucket, RingSet};
use crate::map::Buckets;
Expand Down
3 changes: 1 addition & 2 deletions test-nostd/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
[package]
name = "test-nostd"
version = "0.1.0"
publish = false
edition = "2021"
edition = "2024"

[dependencies.ringmap]
path = ".."
Expand Down
3 changes: 1 addition & 2 deletions test-serde/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
[package]
name = "test-serde"
version = "0.1.0"
publish = false
edition = "2021"
edition = "2024"

[dependencies]

Expand Down
4 changes: 2 additions & 2 deletions test-serde/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#![cfg(test)]

use fnv::FnvBuildHasher;
use ringmap::{ringmap, ringset, RingMap, RingSet};
use ringmap::{RingMap, RingSet, ringmap, ringset};
use serde::{Deserialize, Serialize};
use serde_test::{assert_tokens, Token};
use serde_test::{Token, assert_tokens};

#[test]
fn test_serde_map() {
Expand Down
3 changes: 1 addition & 2 deletions test-sval/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
[package]
name = "test-sval"
version = "0.1.0"
publish = false
edition = "2021"
edition = "2024"

[dependencies]

Expand Down
4 changes: 2 additions & 2 deletions test-sval/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#![cfg(test)]

use fnv::FnvBuildHasher;
use ringmap::{ringmap, ringset, RingMap, RingSet};
use sval_test::{assert_tokens, Token};
use ringmap::{RingMap, RingSet, ringmap, ringset};
use sval_test::{Token, assert_tokens};

#[test]
fn test_sval_map() {
Expand Down
Loading
Loading