Skip to content

Commit ce1d38b

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 041ee54 commit ce1d38b

File tree

3 files changed

+51
-2
lines changed

3 files changed

+51
-2
lines changed

src/map.rs

+20
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,26 @@ where
10311031
}
10321032
}
10331033

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

src/set.rs

+10-1
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, RangeFull, Sub};
14+
use core::ops::{BitAnd, BitOr, BitXor, Index, RangeFull, Sub};
1515
use core::slice;
1616

1717
use super::{Entries, Equivalent, IndexMap};
@@ -602,6 +602,15 @@ impl<T, S> IndexSet<T, S> {
602602
}
603603
}
604604

605+
impl<T, S> Index<usize> for IndexSet<T, S> {
606+
type Output = T;
607+
608+
/// ***Panics*** if `index` is out of bounds.
609+
fn index(&self, index: usize) -> &T {
610+
self.get_index(index).expect("IndexSet: index out of bounds")
611+
}
612+
}
613+
605614
/// An owning iterator over the items of a `IndexSet`.
606615
///
607616
/// This `struct` is created by the [`into_iter`] method on [`IndexSet`]

tests/quick.rs

+21-1
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;
@@ -135,6 +135,26 @@ quickcheck! {
135135
elements.iter().all(|k| map.get(k).is_some())
136136
}
137137

138+
fn indexing(insert: Vec<u8>) -> bool {
139+
let mut map: IndexMap<_, _> = insert.into_iter().map(|x| (x, x)).collect();
140+
let set: IndexSet<_> = map.keys().cloned().collect();
141+
assert_eq!(map.len(), set.len());
142+
143+
for (i, &key) in set.iter().enumerate() {
144+
assert_eq!(map.get_index(i), Some((&key, &key)));
145+
assert_eq!(set.get_index(i), Some(&key));
146+
assert_eq!(map[i], key);
147+
assert_eq!(set[i], key);
148+
149+
*map.get_index_mut(i).unwrap().1 >>= 1;
150+
map[i] <<= 1;
151+
}
152+
153+
set.iter().enumerate().all(|(i, &key)| {
154+
let value = key & !1;
155+
map[&key] == value && map[i] == value
156+
})
157+
}
138158
}
139159

140160
use crate::Op::*;

0 commit comments

Comments
 (0)