Skip to content

Commit 9aa2c9a

Browse files
authored
Merge pull request #4 from cuviper/sync
Sync changes from indexmap and release 0.5.3
2 parents 67dc469 + df53000 commit 9aa2c9a

File tree

7 files changed

+303
-12
lines changed

7 files changed

+303
-12
lines changed

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "ordermap"
33
edition = "2021"
4-
version = "0.5.2"
4+
version = "0.5.3"
55
documentation = "https://docs.rs/ordermap/"
66
repository = "https://github.com/indexmap-rs/ordermap"
77
license = "Apache-2.0 OR MIT"
@@ -14,7 +14,7 @@ rust-version = "1.63"
1414
bench = false
1515

1616
[dependencies]
17-
indexmap = { version = "2.4.0", default-features = false }
17+
indexmap = { version = "2.5.0", default-features = false }
1818

1919
arbitrary = { version = "1.0", optional = true, default-features = false }
2020
quickcheck = { version = "1.0", optional = true, default-features = false }

RELEASES.md

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

3+
## 0.5.3
4+
5+
- Added an `insert_before` method to `OrderMap` and `OrderSet`, as an
6+
alternative to `shift_insert` with different behavior on existing entries.
7+
- Added `first_entry` and `last_entry` methods to `OrderMap`.
8+
- Added `From` implementations between `IndexedEntry` and `OccupiedEntry`.
9+
310
## 0.5.2
411

512
- Added methods `OrderMap::append` and `OrderSet::append`, moving all items from

src/map.rs

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ where
393393
///
394394
/// This is equivalent to finding the position with
395395
/// [`binary_search_keys`][Self::binary_search_keys], then either updating
396-
/// it or calling [`shift_insert`][Self::shift_insert] for a new key.
396+
/// it or calling [`insert_before`][Self::insert_before] for a new key.
397397
///
398398
/// If the sorted key is found in the map, its corresponding value is
399399
/// updated with `value`, and the older value is returned inside
@@ -415,21 +415,115 @@ where
415415
self.inner.insert_sorted(key, value)
416416
}
417417

418-
/// Insert a key-value pair in the map at the given index.
418+
/// Insert a key-value pair in the map before the entry at the given index, or at the end.
419419
///
420420
/// If an equivalent key already exists in the map: the key remains and
421421
/// is moved to the new position in the map, its corresponding value is updated
422+
/// with `value`, and the older value is returned inside `Some(_)`. The returned index
423+
/// will either be the given index or one less, depending on how the entry moved.
424+
/// (See [`shift_insert`](Self::shift_insert) for different behavior here.)
425+
///
426+
/// If no equivalent key existed in the map: the new key-value pair is
427+
/// inserted exactly at the given index, and `None` is returned.
428+
///
429+
/// ***Panics*** if `index` is out of bounds.
430+
/// Valid indices are `0..=map.len()` (inclusive).
431+
///
432+
/// Computes in **O(n)** time (average).
433+
///
434+
/// See also [`entry`][Self::entry] if you want to insert *or* modify,
435+
/// perhaps only using the index for new entries with [`VacantEntry::shift_insert`].
436+
///
437+
/// # Examples
438+
///
439+
/// ```
440+
/// use ordermap::OrderMap;
441+
/// let mut map: OrderMap<char, ()> = ('a'..='z').map(|c| (c, ())).collect();
442+
///
443+
/// // The new key '*' goes exactly at the given index.
444+
/// assert_eq!(map.get_index_of(&'*'), None);
445+
/// assert_eq!(map.insert_before(10, '*', ()), (10, None));
446+
/// assert_eq!(map.get_index_of(&'*'), Some(10));
447+
///
448+
/// // Moving the key 'a' up will shift others down, so this moves *before* 10 to index 9.
449+
/// assert_eq!(map.insert_before(10, 'a', ()), (9, Some(())));
450+
/// assert_eq!(map.get_index_of(&'a'), Some(9));
451+
/// assert_eq!(map.get_index_of(&'*'), Some(10));
452+
///
453+
/// // Moving the key 'z' down will shift others up, so this moves to exactly 10.
454+
/// assert_eq!(map.insert_before(10, 'z', ()), (10, Some(())));
455+
/// assert_eq!(map.get_index_of(&'z'), Some(10));
456+
/// assert_eq!(map.get_index_of(&'*'), Some(11));
457+
///
458+
/// // Moving or inserting before the endpoint is also valid.
459+
/// assert_eq!(map.len(), 27);
460+
/// assert_eq!(map.insert_before(map.len(), '*', ()), (26, Some(())));
461+
/// assert_eq!(map.get_index_of(&'*'), Some(26));
462+
/// assert_eq!(map.insert_before(map.len(), '+', ()), (27, None));
463+
/// assert_eq!(map.get_index_of(&'+'), Some(27));
464+
/// assert_eq!(map.len(), 28);
465+
/// ```
466+
pub fn insert_before(&mut self, index: usize, key: K, value: V) -> (usize, Option<V>) {
467+
self.inner.insert_before(index, key, value)
468+
}
469+
470+
/// Insert a key-value pair in the map at the given index.
471+
///
472+
/// If an equivalent key already exists in the map: the key remains and
473+
/// is moved to the given index in the map, its corresponding value is updated
422474
/// with `value`, and the older value is returned inside `Some(_)`.
475+
/// Note that existing entries **cannot** be moved to `index == map.len()`!
476+
/// (See [`insert_before`](Self::insert_before) for different behavior here.)
423477
///
424478
/// If no equivalent key existed in the map: the new key-value pair is
425479
/// inserted at the given index, and `None` is returned.
426480
///
427481
/// ***Panics*** if `index` is out of bounds.
482+
/// Valid indices are `0..map.len()` (exclusive) when moving an existing entry, or
483+
/// `0..=map.len()` (inclusive) when inserting a new key.
428484
///
429485
/// Computes in **O(n)** time (average).
430486
///
431487
/// See also [`entry`][Self::entry] if you want to insert *or* modify,
432488
/// perhaps only using the index for new entries with [`VacantEntry::shift_insert`].
489+
///
490+
/// # Examples
491+
///
492+
/// ```
493+
/// use ordermap::OrderMap;
494+
/// let mut map: OrderMap<char, ()> = ('a'..='z').map(|c| (c, ())).collect();
495+
///
496+
/// // The new key '*' goes exactly at the given index.
497+
/// assert_eq!(map.get_index_of(&'*'), None);
498+
/// assert_eq!(map.shift_insert(10, '*', ()), None);
499+
/// assert_eq!(map.get_index_of(&'*'), Some(10));
500+
///
501+
/// // Moving the key 'a' up to 10 will shift others down, including the '*' that was at 10.
502+
/// assert_eq!(map.shift_insert(10, 'a', ()), Some(()));
503+
/// assert_eq!(map.get_index_of(&'a'), Some(10));
504+
/// assert_eq!(map.get_index_of(&'*'), Some(9));
505+
///
506+
/// // Moving the key 'z' down to 9 will shift others up, including the '*' that was at 9.
507+
/// assert_eq!(map.shift_insert(9, 'z', ()), Some(()));
508+
/// assert_eq!(map.get_index_of(&'z'), Some(9));
509+
/// assert_eq!(map.get_index_of(&'*'), Some(10));
510+
///
511+
/// // Existing keys can move to len-1 at most, but new keys can insert at the endpoint.
512+
/// assert_eq!(map.len(), 27);
513+
/// assert_eq!(map.shift_insert(map.len() - 1, '*', ()), Some(()));
514+
/// assert_eq!(map.get_index_of(&'*'), Some(26));
515+
/// assert_eq!(map.shift_insert(map.len(), '+', ()), None);
516+
/// assert_eq!(map.get_index_of(&'+'), Some(27));
517+
/// assert_eq!(map.len(), 28);
518+
/// ```
519+
///
520+
/// ```should_panic
521+
/// use ordermap::OrderMap;
522+
/// let mut map: OrderMap<char, ()> = ('a'..='z').map(|c| (c, ())).collect();
523+
///
524+
/// // This is an invalid index for moving an existing key!
525+
/// map.shift_insert(map.len(), 'a', ());
526+
/// ```
433527
pub fn shift_insert(&mut self, index: usize, key: K, value: V) -> Option<V> {
434528
self.inner.shift_insert(index, key, value)
435529
}
@@ -687,6 +781,7 @@ impl<K, V, S> OrderMap<K, V, S> {
687781
/// This preserves the order of the remaining elements.
688782
///
689783
/// Computes in **O(1)** time (average).
784+
#[doc(alias = "pop_last")] // like `BTreeMap`
690785
pub fn pop(&mut self) -> Option<(K, V)> {
691786
self.inner.pop()
692787
}
@@ -932,6 +1027,7 @@ impl<K, V, S> OrderMap<K, V, S> {
9321027
/// Get the first key-value pair
9331028
///
9341029
/// Computes in **O(1)** time.
1030+
#[doc(alias = "first_key_value")] // like `BTreeMap`
9351031
pub fn first(&self) -> Option<(&K, &V)> {
9361032
self.inner.first()
9371033
}
@@ -943,9 +1039,17 @@ impl<K, V, S> OrderMap<K, V, S> {
9431039
self.inner.first_mut()
9441040
}
9451041

1042+
/// Get the first entry in the map for in-place manipulation.
1043+
///
1044+
/// Computes in **O(1)** time.
1045+
pub fn first_entry(&mut self) -> Option<IndexedEntry<'_, K, V>> {
1046+
self.inner.first_entry().map(IndexedEntry::new)
1047+
}
1048+
9461049
/// Get the last key-value pair
9471050
///
9481051
/// Computes in **O(1)** time.
1052+
#[doc(alias = "last_key_value")] // like `BTreeMap`
9491053
pub fn last(&self) -> Option<(&K, &V)> {
9501054
self.inner.last()
9511055
}
@@ -957,6 +1061,13 @@ impl<K, V, S> OrderMap<K, V, S> {
9571061
self.inner.last_mut()
9581062
}
9591063

1064+
/// Get the last entry in the map for in-place manipulation.
1065+
///
1066+
/// Computes in **O(1)** time.
1067+
pub fn last_entry(&mut self) -> Option<IndexedEntry<'_, K, V>> {
1068+
self.inner.last_entry().map(IndexedEntry::new)
1069+
}
1070+
9601071
/// Remove the key-value pair by index
9611072
///
9621073
/// Valid indices are *0 <= index < self.len()*

src/map/entry.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,14 @@ impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for OccupiedEntry<'_, K, V> {
250250
}
251251
}
252252

253+
impl<'a, K, V> From<IndexedEntry<'a, K, V>> for OccupiedEntry<'a, K, V> {
254+
fn from(entry: IndexedEntry<'a, K, V>) -> Self {
255+
Self {
256+
inner: entry.inner.into(),
257+
}
258+
}
259+
}
260+
253261
/// A view into a vacant entry in an [`OrderMap`][crate::OrderMap].
254262
/// It is part of the [`Entry`] enum.
255263
pub struct VacantEntry<'a, K, V> {
@@ -444,3 +452,11 @@ impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for IndexedEntry<'_, K, V> {
444452
.finish()
445453
}
446454
}
455+
456+
impl<'a, K, V> From<OccupiedEntry<'a, K, V>> for IndexedEntry<'a, K, V> {
457+
fn from(entry: OccupiedEntry<'a, K, V>) -> Self {
458+
Self {
459+
inner: entry.inner.into(),
460+
}
461+
}
462+
}

src/map/mutable.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ where
9999
/// This trait is sealed and cannot be implemented for types outside this crate.
100100
pub trait MutableEntryKey: private::Sealed {
101101
type Key;
102+
103+
/// Gets a mutable reference to the entry's key, either within the map if occupied,
104+
/// or else the new key that was used to find the entry.
102105
fn key_mut(&mut self) -> &mut Self::Key;
103106
}
104107

@@ -107,9 +110,6 @@ pub trait MutableEntryKey: private::Sealed {
107110
/// See [`MutableEntryKey`] for more information.
108111
impl<K, V> MutableEntryKey for Entry<'_, K, V> {
109112
type Key = K;
110-
111-
/// Gets a mutable reference to the entry's key, either within the map if occupied,
112-
/// or else the new key that was used to find the entry.
113113
fn key_mut(&mut self) -> &mut Self::Key {
114114
match self {
115115
Entry::Occupied(e) => e.key_mut(),

src/map/tests.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,34 @@ fn shift_insert() {
136136
}
137137
}
138138

139+
#[test]
140+
fn insert_sorted_bad() {
141+
let mut map = OrderMap::new();
142+
map.insert(10, ());
143+
for i in 0..10 {
144+
map.insert(i, ());
145+
}
146+
147+
// The binary search will want to insert this at the end (index == len()),
148+
// but that's only possible for *new* inserts. It should still be handled
149+
// without panicking though, and in this case it's simple enough that we
150+
// know the exact result. (But don't read this as an API guarantee!)
151+
assert_eq!(map.first(), Some((&10, &())));
152+
map.insert_sorted(10, ());
153+
assert_eq!(map.last(), Some((&10, &())));
154+
assert!(map.keys().copied().eq(0..=10));
155+
156+
// Other out-of-order entries can also "insert" to a binary-searched
157+
// position, moving in either direction.
158+
map.move_index(5, 0);
159+
map.move_index(6, 10);
160+
assert_eq!(map.first(), Some((&5, &())));
161+
assert_eq!(map.last(), Some((&6, &())));
162+
map.insert_sorted(5, ()); // moves back up
163+
map.insert_sorted(6, ()); // moves back down
164+
assert!(map.keys().copied().eq(0..=10));
165+
}
166+
139167
#[test]
140168
fn grow() {
141169
let insert = [0, 4, 2, 12, 8, 7, 11];
@@ -388,6 +416,8 @@ fn get_index_entry() {
388416
let mut map = OrderMap::new();
389417

390418
assert!(map.get_index_entry(0).is_none());
419+
assert!(map.first_entry().is_none());
420+
assert!(map.last_entry().is_none());
391421

392422
map.insert(0, "0");
393423
map.insert(1, "1");
@@ -411,6 +441,43 @@ fn get_index_entry() {
411441
}
412442

413443
assert_eq!(*map.get(&3).unwrap(), "4");
444+
445+
{
446+
let e = map.first_entry().unwrap();
447+
assert_eq!(*e.key(), 0);
448+
assert_eq!(*e.get(), "0");
449+
}
450+
451+
{
452+
let e = map.last_entry().unwrap();
453+
assert_eq!(*e.key(), 2);
454+
assert_eq!(*e.get(), "2");
455+
}
456+
}
457+
458+
#[test]
459+
fn from_entries() {
460+
let mut map = OrderMap::from([(1, "1"), (2, "2"), (3, "3")]);
461+
462+
{
463+
let e = match map.entry(1) {
464+
Entry::Occupied(e) => IndexedEntry::from(e),
465+
Entry::Vacant(_) => panic!(),
466+
};
467+
assert_eq!(e.index(), 0);
468+
assert_eq!(*e.key(), 1);
469+
assert_eq!(*e.get(), "1");
470+
}
471+
472+
{
473+
let e = match map.get_index_entry(1) {
474+
Some(e) => OccupiedEntry::from(e),
475+
None => panic!(),
476+
};
477+
assert_eq!(e.index(), 1);
478+
assert_eq!(*e.key(), 2);
479+
assert_eq!(*e.get(), "2");
480+
}
414481
}
415482

416483
#[test]

0 commit comments

Comments
 (0)