Skip to content

Commit f0ec924

Browse files
authored
Merge pull request #367 from savannstm/better-panics
Improve panic messages and add `#[track_caller]` attribute to functions that may panic
2 parents 38ef618 + 2f55755 commit f0ec924

File tree

7 files changed

+75
-13
lines changed

7 files changed

+75
-13
lines changed

src/map.rs

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@ impl<K, V, S> IndexMap<K, V, S> {
299299
///
300300
/// ***Panics*** if the starting point is greater than the end point or if
301301
/// the end point is greater than the length of the map.
302+
#[track_caller]
302303
pub fn drain<R>(&mut self, range: R) -> Drain<'_, K, V>
303304
where
304305
R: RangeBounds<usize>,
@@ -313,6 +314,7 @@ impl<K, V, S> IndexMap<K, V, S> {
313314
/// the elements `[0, at)` with its previous capacity unchanged.
314315
///
315316
/// ***Panics*** if `at > len`.
317+
#[track_caller]
316318
pub fn split_off(&mut self, at: usize) -> Self
317319
where
318320
S: Clone,
@@ -493,8 +495,15 @@ where
493495
/// assert_eq!(map.get_index_of(&'+'), Some(27));
494496
/// assert_eq!(map.len(), 28);
495497
/// ```
498+
#[track_caller]
496499
pub fn insert_before(&mut self, mut index: usize, key: K, value: V) -> (usize, Option<V>) {
497-
assert!(index <= self.len(), "index out of bounds");
500+
let len = self.len();
501+
502+
assert!(
503+
index <= len,
504+
"index out of bounds: the len is {len} but the index is {index}. Expected index <= len"
505+
);
506+
498507
match self.entry(key) {
499508
Entry::Occupied(mut entry) => {
500509
if index > entry.index() {
@@ -571,17 +580,26 @@ where
571580
/// // This is an invalid index for moving an existing key!
572581
/// map.shift_insert(map.len(), 'a', ());
573582
/// ```
583+
#[track_caller]
574584
pub fn shift_insert(&mut self, index: usize, key: K, value: V) -> Option<V> {
575585
let len = self.len();
576586
match self.entry(key) {
577587
Entry::Occupied(mut entry) => {
578-
assert!(index < len, "index out of bounds");
588+
assert!(
589+
index < len,
590+
"index out of bounds: the len is {len} but the index is {index}"
591+
);
592+
579593
let old = mem::replace(entry.get_mut(), value);
580594
entry.move_index(index);
581595
Some(old)
582596
}
583597
Entry::Vacant(entry) => {
584-
assert!(index <= len, "index out of bounds");
598+
assert!(
599+
index <= len,
600+
"index out of bounds: the len is {len} but the index is {index}. Expected index <= len"
601+
);
602+
585603
entry.shift_insert(index, value);
586604
None
587605
}
@@ -627,6 +645,7 @@ where
627645
/// assert!(map.into_iter().eq([(0, '_'), (1, 'A'), (5, 'E'), (3, 'C'), (2, 'B'), (4, 'D')]));
628646
/// assert_eq!(removed, &[(2, 'b'), (3, 'c')]);
629647
/// ```
648+
#[track_caller]
630649
pub fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter, K, V, S>
631650
where
632651
R: RangeBounds<usize>,
@@ -1278,6 +1297,7 @@ impl<K, V, S> IndexMap<K, V, S> {
12781297
/// ***Panics*** if `from` or `to` are out of bounds.
12791298
///
12801299
/// Computes in **O(n)** time (average).
1300+
#[track_caller]
12811301
pub fn move_index(&mut self, from: usize, to: usize) {
12821302
self.core.move_index(from, to)
12831303
}
@@ -1287,6 +1307,7 @@ impl<K, V, S> IndexMap<K, V, S> {
12871307
/// ***Panics*** if `a` or `b` are out of bounds.
12881308
///
12891309
/// Computes in **O(1)** time (average).
1310+
#[track_caller]
12901311
pub fn swap_indices(&mut self, a: usize, b: usize) {
12911312
self.core.swap_indices(a, b)
12921313
}
@@ -1325,7 +1346,7 @@ where
13251346
///
13261347
/// ***Panics*** if `key` is not present in the map.
13271348
fn index(&self, key: &Q) -> &V {
1328-
self.get(key).expect("IndexMap: key not found")
1349+
self.get(key).expect("no entry found for key")
13291350
}
13301351
}
13311352

@@ -1367,7 +1388,7 @@ where
13671388
///
13681389
/// ***Panics*** if `key` is not present in the map.
13691390
fn index_mut(&mut self, key: &Q) -> &mut V {
1370-
self.get_mut(key).expect("IndexMap: key not found")
1391+
self.get_mut(key).expect("no entry found for key")
13711392
}
13721393
}
13731394

@@ -1411,7 +1432,12 @@ impl<K, V, S> Index<usize> for IndexMap<K, V, S> {
14111432
/// ***Panics*** if `index` is out of bounds.
14121433
fn index(&self, index: usize) -> &V {
14131434
self.get_index(index)
1414-
.expect("IndexMap: index out of bounds")
1435+
.unwrap_or_else(|| {
1436+
panic!(
1437+
"index out of bounds: the len is {len} but the index is {index}",
1438+
len = self.len()
1439+
);
1440+
})
14151441
.1
14161442
}
14171443
}
@@ -1450,8 +1476,12 @@ impl<K, V, S> IndexMut<usize> for IndexMap<K, V, S> {
14501476
///
14511477
/// ***Panics*** if `index` is out of bounds.
14521478
fn index_mut(&mut self, index: usize) -> &mut V {
1479+
let len: usize = self.len();
1480+
14531481
self.get_index_mut(index)
1454-
.expect("IndexMap: index out of bounds")
1482+
.unwrap_or_else(|| {
1483+
panic!("index out of bounds: the len is {len} but the index is {index}");
1484+
})
14551485
.1
14561486
}
14571487
}

src/map/core.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ impl<K, V> IndexMapCore<K, V> {
183183
}
184184
}
185185

186+
#[track_caller]
186187
pub(crate) fn drain<R>(&mut self, range: R) -> vec::Drain<'_, Bucket<K, V>>
187188
where
188189
R: RangeBounds<usize>,
@@ -205,8 +206,14 @@ impl<K, V> IndexMapCore<K, V> {
205206
self.entries.par_drain(range)
206207
}
207208

209+
#[track_caller]
208210
pub(crate) fn split_off(&mut self, at: usize) -> Self {
209-
assert!(at <= self.entries.len());
211+
let len = self.entries.len();
212+
assert!(
213+
at <= len,
214+
"index out of bounds: the len is {len} but the index is {at}. Expected index <= len"
215+
);
216+
210217
self.erase_indices(at, self.entries.len());
211218
let entries = self.entries.split_off(at);
212219

@@ -215,6 +222,7 @@ impl<K, V> IndexMapCore<K, V> {
215222
Self { indices, entries }
216223
}
217224

225+
#[track_caller]
218226
pub(crate) fn split_splice<R>(&mut self, range: R) -> (Self, vec::IntoIter<Bucket<K, V>>)
219227
where
220228
R: RangeBounds<usize>,
@@ -403,11 +411,13 @@ impl<K, V> IndexMapCore<K, V> {
403411
}
404412

405413
#[inline]
414+
#[track_caller]
406415
pub(super) fn move_index(&mut self, from: usize, to: usize) {
407416
self.borrow_mut().move_index(from, to);
408417
}
409418

410419
#[inline]
420+
#[track_caller]
411421
pub(crate) fn swap_indices(&mut self, a: usize, b: usize) {
412422
self.borrow_mut().swap_indices(a, b);
413423
}
@@ -670,6 +680,7 @@ impl<'a, K, V> RefMut<'a, K, V> {
670680
}
671681
}
672682

683+
#[track_caller]
673684
fn move_index(&mut self, from: usize, to: usize) {
674685
let from_hash = self.entries[from].hash;
675686
let _ = self.entries[to]; // explicit bounds check
@@ -691,6 +702,7 @@ impl<'a, K, V> RefMut<'a, K, V> {
691702
}
692703
}
693704

705+
#[track_caller]
694706
fn swap_indices(&mut self, a: usize, b: usize) {
695707
// If they're equal and in-bounds, there's nothing to do.
696708
if a == b && a < self.entries.len() {

src/map/core/entry.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> {
294294
/// ***Panics*** if `to` is out of bounds.
295295
///
296296
/// Computes in **O(n)** time (average).
297+
#[track_caller]
297298
pub fn move_index(self, to: usize) {
298299
let index = self.index();
299300
self.into_ref_mut().move_index(index, to);
@@ -532,6 +533,7 @@ impl<'a, K, V> IndexedEntry<'a, K, V> {
532533
/// ***Panics*** if `to` is out of bounds.
533534
///
534535
/// Computes in **O(n)** time (average).
536+
#[track_caller]
535537
pub fn move_index(mut self, to: usize) {
536538
self.map.move_index(self.index, to);
537539
}

src/map/iter.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,7 @@ where
667667
K: Hash + Eq,
668668
S: BuildHasher,
669669
{
670+
#[track_caller]
670671
pub(super) fn new<R>(map: &'a mut IndexMap<K, V, S>, range: R, replace_with: I) -> Self
671672
where
672673
R: RangeBounds<usize>,

src/set.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ impl<T, S> IndexSet<T, S> {
250250
///
251251
/// ***Panics*** if the starting point is greater than the end point or if
252252
/// the end point is greater than the length of the set.
253+
#[track_caller]
253254
pub fn drain<R>(&mut self, range: R) -> Drain<'_, T>
254255
where
255256
R: RangeBounds<usize>,
@@ -264,6 +265,7 @@ impl<T, S> IndexSet<T, S> {
264265
/// the elements `[0, at)` with its previous capacity unchanged.
265266
///
266267
/// ***Panics*** if `at > len`.
268+
#[track_caller]
267269
pub fn split_off(&mut self, at: usize) -> Self
268270
where
269271
S: Clone,
@@ -426,6 +428,7 @@ where
426428
/// assert_eq!(set.get_index_of(&'+'), Some(27));
427429
/// assert_eq!(set.len(), 28);
428430
/// ```
431+
#[track_caller]
429432
pub fn insert_before(&mut self, index: usize, value: T) -> (usize, bool) {
430433
let (index, existing) = self.map.insert_before(index, value, ());
431434
(index, existing.is_none())
@@ -483,6 +486,7 @@ where
483486
/// // This is an invalid index for moving an existing value!
484487
/// set.shift_insert(set.len(), 'a');
485488
/// ```
489+
#[track_caller]
486490
pub fn shift_insert(&mut self, index: usize, value: T) -> bool {
487491
self.map.shift_insert(index, value, ()).is_none()
488492
}
@@ -584,6 +588,7 @@ where
584588
/// assert!(set.into_iter().eq([0, 1, 5, 3, 2, 4]));
585589
/// assert_eq!(removed, &[2, 3]);
586590
/// ```
591+
#[track_caller]
587592
pub fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter, T, S>
588593
where
589594
R: RangeBounds<usize>,
@@ -1050,6 +1055,7 @@ impl<T, S> IndexSet<T, S> {
10501055
/// ***Panics*** if `from` or `to` are out of bounds.
10511056
///
10521057
/// Computes in **O(n)** time (average).
1058+
#[track_caller]
10531059
pub fn move_index(&mut self, from: usize, to: usize) {
10541060
self.map.move_index(from, to)
10551061
}
@@ -1059,6 +1065,7 @@ impl<T, S> IndexSet<T, S> {
10591065
/// ***Panics*** if `a` or `b` are out of bounds.
10601066
///
10611067
/// Computes in **O(1)** time (average).
1068+
#[track_caller]
10621069
pub fn swap_indices(&mut self, a: usize, b: usize) {
10631070
self.map.swap_indices(a, b)
10641071
}
@@ -1099,8 +1106,12 @@ impl<T, S> Index<usize> for IndexSet<T, S> {
10991106
///
11001107
/// ***Panics*** if `index` is out of bounds.
11011108
fn index(&self, index: usize) -> &T {
1102-
self.get_index(index)
1103-
.expect("IndexSet: index out of bounds")
1109+
self.get_index(index).unwrap_or_else(|| {
1110+
panic!(
1111+
"index out of bounds: the len is {len} but the index is {index}",
1112+
len = self.len()
1113+
);
1114+
})
11041115
}
11051116
}
11061117

src/set/iter.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,7 @@ where
542542
T: Hash + Eq,
543543
S: BuildHasher,
544544
{
545+
#[track_caller]
545546
pub(super) fn new<R>(set: &'a mut IndexSet<T, S>, range: R, replace_with: I) -> Self
546547
where
547548
R: RangeBounds<usize>,

src/util.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pub(crate) fn third<A, B, C>(t: (A, B, C)) -> C {
44
t.2
55
}
66

7+
#[track_caller]
78
pub(crate) fn simplify_range<R>(range: R, len: usize) -> Range<usize>
89
where
910
R: RangeBounds<usize>,
@@ -12,17 +13,21 @@ where
1213
Bound::Unbounded => 0,
1314
Bound::Included(&i) if i <= len => i,
1415
Bound::Excluded(&i) if i < len => i + 1,
15-
bound => panic!("range start {:?} should be <= length {}", bound, len),
16+
Bound::Included(i) | Bound::Excluded(i) => {
17+
panic!("range start index {i} out of range for slice of length {len}")
18+
}
1619
};
1720
let end = match range.end_bound() {
1821
Bound::Unbounded => len,
1922
Bound::Excluded(&i) if i <= len => i,
2023
Bound::Included(&i) if i < len => i + 1,
21-
bound => panic!("range end {:?} should be <= length {}", bound, len),
24+
Bound::Included(i) | Bound::Excluded(i) => {
25+
panic!("range end index {i} out of range for slice of length {len}")
26+
}
2227
};
2328
if start > end {
2429
panic!(
25-
"range start {:?} should be <= range end {:?}",
30+
"range start index {:?} should be <= range end index {:?}",
2631
range.start_bound(),
2732
range.end_bound()
2833
);

0 commit comments

Comments
 (0)