Skip to content

Commit 0532ea1

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 43b5fac commit 0532ea1

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
@@ -980,6 +980,26 @@ where
980980
}
981981
}
982982

983+
impl<K, V, S> Index<usize> for IndexMap<K, V, S> {
984+
type Output = V;
985+
986+
/// ***Panics*** if `index` is out of bounds.
987+
fn index(&self, index: usize) -> &V {
988+
self.get_index(index).expect("IndexMap: index out of bounds").1
989+
}
990+
}
991+
992+
/// Mutable indexing allows changing / updating indexed values
993+
/// that are already present.
994+
///
995+
/// You can **not** insert new values with index syntax, use `.insert()`.
996+
impl<K, V, S> IndexMut<usize> for IndexMap<K, V, S> {
997+
/// ***Panics*** if `index` is out of bounds.
998+
fn index_mut(&mut self, index: usize) -> &mut V {
999+
self.get_index_mut(index).expect("IndexMap: index out of bounds").1
1000+
}
1001+
}
1002+
9831003
impl<K, V, S> FromIterator<(K, V)> for IndexMap<K, V, S>
9841004
where
9851005
K: Hash + Eq,

src/set.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use std::fmt;
1414
use std::hash::{BuildHasher, Hash};
1515
use std::iter::{Chain, FromIterator};
1616
use std::ops::RangeFull;
17-
use std::ops::{BitAnd, BitOr, BitXor, Sub};
17+
use std::ops::{BitAnd, BitOr, BitXor, Index, Sub};
1818
use std::slice;
1919
use std::vec;
2020

@@ -594,6 +594,15 @@ impl<T, S> IndexSet<T, S> {
594594
}
595595
}
596596

597+
impl<T, S> Index<usize> for IndexSet<T, S> {
598+
type Output = T;
599+
600+
/// ***Panics*** if `index` is out of bounds.
601+
fn index(&self, index: usize) -> &T {
602+
self.get_index(index).expect("IndexSet: index out of bounds")
603+
}
604+
}
605+
597606
/// An owning iterator over the items of a `IndexSet`.
598607
///
599608
/// This `struct` is created by the [`into_iter`] method on [`IndexSet`]

tests/quick.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ extern crate rand;
66

77
extern crate fnv;
88

9-
use indexmap::IndexMap;
9+
use indexmap::{IndexMap, IndexSet};
1010
use itertools::Itertools;
1111

1212
use quickcheck::Arbitrary;
@@ -142,6 +142,26 @@ quickcheck! {
142142
elements.iter().all(|k| map.get(k).is_some())
143143
}
144144

145+
fn indexing(insert: Vec<u8>) -> bool {
146+
let mut map: IndexMap<_, _> = insert.into_iter().map(|x| (x, x)).collect();
147+
let set: IndexSet<_> = map.keys().cloned().collect();
148+
assert_eq!(map.len(), set.len());
149+
150+
for (i, &key) in set.iter().enumerate() {
151+
assert_eq!(map.get_index(i), Some((&key, &key)));
152+
assert_eq!(set.get_index(i), Some(&key));
153+
assert_eq!(map[i], key);
154+
assert_eq!(set[i], key);
155+
156+
*map.get_index_mut(i).unwrap().1 >>= 1;
157+
map[i] <<= 1;
158+
}
159+
160+
set.iter().enumerate().all(|(i, &key)| {
161+
let value = key & !1;
162+
map[&key] == value && map[i] == value
163+
})
164+
}
145165
}
146166

147167
use Op::*;

0 commit comments

Comments
 (0)