Skip to content

Commit 7378003

Browse files
committed
Implement direct usize indexing
```rust where IndexMap<K, V, S>: IndexMut<usize, Output = V>, IndexSet<T, S>: Index<usize, Output = T>, ``` This allows `map[i]` and `set[i]` indexing to access values directly, panicking if the index is out of bounds, similar to slices. On maps, this somewhat overlaps with `Index<&Q> + IndexMut<&Q>` where `Q: Equivalent<K>`. The reference makes this indexing unambiguous, but it could be confusing to users if the key type is also an integer.
1 parent 8ddc4f1 commit 7378003

File tree

3 files changed

+56
-2
lines changed

3 files changed

+56
-2
lines changed

src/map.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,30 @@ where
10231023
}
10241024
}
10251025

1026+
impl<K, V, S> Index<usize> for IndexMap<K, V, S> {
1027+
type Output = V;
1028+
1029+
/// ***Panics*** if `index` is out of bounds.
1030+
fn index(&self, index: usize) -> &V {
1031+
self.get_index(index)
1032+
.expect("IndexMap: index out of bounds")
1033+
.1
1034+
}
1035+
}
1036+
1037+
/// Mutable indexing allows changing / updating indexed values
1038+
/// that are already present.
1039+
///
1040+
/// You can **not** insert new values with index syntax, use `.insert()`.
1041+
impl<K, V, S> IndexMut<usize> for IndexMap<K, V, S> {
1042+
/// ***Panics*** if `index` is out of bounds.
1043+
fn index_mut(&mut self, index: usize) -> &mut V {
1044+
self.get_index_mut(index)
1045+
.expect("IndexMap: index out of bounds")
1046+
.1
1047+
}
1048+
}
1049+
10261050
impl<K, V, S> FromIterator<(K, V)> for IndexMap<K, V, S>
10271051
where
10281052
K: Hash + Eq,

src/set.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use core::cmp::Ordering;
1111
use core::fmt;
1212
use core::hash::{BuildHasher, Hash};
1313
use core::iter::{Chain, FromIterator};
14-
use core::ops::{BitAnd, BitOr, BitXor, RangeBounds, Sub};
14+
use core::ops::{BitAnd, BitOr, BitXor, Index, RangeBounds, Sub};
1515
use core::slice;
1616

1717
use super::{Entries, Equivalent, IndexMap};
@@ -606,6 +606,16 @@ impl<T, S> IndexSet<T, S> {
606606
}
607607
}
608608

609+
impl<T, S> Index<usize> for IndexSet<T, S> {
610+
type Output = T;
611+
612+
/// ***Panics*** if `index` is out of bounds.
613+
fn index(&self, index: usize) -> &T {
614+
self.get_index(index)
615+
.expect("IndexSet: index out of bounds")
616+
}
617+
}
618+
609619
/// An owning iterator over the items of a `IndexSet`.
610620
///
611621
/// This `struct` is created by the [`into_iter`] method on [`IndexSet`]

tests/quick.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use indexmap::IndexMap;
1+
use indexmap::{IndexMap, IndexSet};
22
use itertools::Itertools;
33

44
use quickcheck::quickcheck;
@@ -163,6 +163,26 @@ quickcheck! {
163163
elements.iter().all(|k| map.get(k).is_some())
164164
}
165165

166+
fn indexing(insert: Vec<u8>) -> bool {
167+
let mut map: IndexMap<_, _> = insert.into_iter().map(|x| (x, x)).collect();
168+
let set: IndexSet<_> = map.keys().cloned().collect();
169+
assert_eq!(map.len(), set.len());
170+
171+
for (i, &key) in set.iter().enumerate() {
172+
assert_eq!(map.get_index(i), Some((&key, &key)));
173+
assert_eq!(set.get_index(i), Some(&key));
174+
assert_eq!(map[i], key);
175+
assert_eq!(set[i], key);
176+
177+
*map.get_index_mut(i).unwrap().1 >>= 1;
178+
map[i] <<= 1;
179+
}
180+
181+
set.iter().enumerate().all(|(i, &key)| {
182+
let value = key & !1;
183+
map[&key] == value && map[i] == value
184+
})
185+
}
166186
}
167187

168188
use crate::Op::*;

0 commit comments

Comments
 (0)