Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 8426154

Browse files
authoredFeb 11, 2021
Rollup merge of rust-lang#81154 - dylni:improve-design-of-assert-len, r=KodrAus
Improve design of `assert_len` It was discussed in the [tracking issue](rust-lang#76393 (comment)) that `assert_len`'s name and usage are confusing. This PR improves them based on a suggestion by `@scottmcm` in that issue. I also improved the documentation to make it clearer when you might want to use this method. Old example: ```rust let range = range.assert_len(slice.len()); ``` New example: ```rust let range = range.ensure_subset_of(..slice.len()); ``` Fixes rust-lang#81157
2 parents c202114 + dd1ab4c commit 8426154

File tree

9 files changed

+115
-111
lines changed

9 files changed

+115
-111
lines changed
 

‎library/alloc/src/collections/vec_deque/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1063,7 +1063,7 @@ impl<T> VecDeque<T> {
10631063
where
10641064
R: RangeBounds<usize>,
10651065
{
1066-
let Range { start, end } = range.assert_len(self.len());
1066+
let Range { start, end } = slice::range(range, ..self.len());
10671067
let tail = self.wrap_add(self.tail, start);
10681068
let head = self.wrap_add(self.tail, end);
10691069
(tail, head)

‎library/alloc/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -115,14 +115,14 @@
115115
#![feature(or_patterns)]
116116
#![feature(pattern)]
117117
#![feature(ptr_internals)]
118-
#![feature(range_bounds_assert_len)]
119118
#![feature(rustc_attrs)]
120119
#![feature(receiver_trait)]
121120
#![cfg_attr(bootstrap, feature(min_const_generics))]
122121
#![feature(min_specialization)]
123122
#![feature(set_ptr_value)]
124123
#![feature(slice_ptr_get)]
125124
#![feature(slice_ptr_len)]
125+
#![feature(slice_range)]
126126
#![feature(staged_api)]
127127
#![feature(str_internals)]
128128
#![feature(trusted_len)]

‎library/alloc/src/slice.rs

+2
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ use crate::borrow::ToOwned;
9292
use crate::boxed::Box;
9393
use crate::vec::Vec;
9494

95+
#[unstable(feature = "slice_range", issue = "76393")]
96+
pub use core::slice::range;
9597
#[unstable(feature = "array_chunks", issue = "74985")]
9698
pub use core::slice::ArrayChunks;
9799
#[unstable(feature = "array_chunks", issue = "74985")]

‎library/alloc/src/string.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ use core::iter::{FromIterator, FusedIterator};
4949
use core::ops::Bound::{Excluded, Included, Unbounded};
5050
use core::ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds};
5151
use core::ptr;
52+
use core::slice;
5253
use core::str::{lossy, pattern::Pattern};
5354

5455
use crate::borrow::{Cow, ToOwned};
@@ -1510,14 +1511,14 @@ impl String {
15101511
// of the vector version. The data is just plain bytes.
15111512
// Because the range removal happens in Drop, if the Drain iterator is leaked,
15121513
// the removal will not happen.
1513-
let Range { start, end } = range.assert_len(self.len());
1514+
let Range { start, end } = slice::range(range, ..self.len());
15141515
assert!(self.is_char_boundary(start));
15151516
assert!(self.is_char_boundary(end));
15161517

15171518
// Take out two simultaneous borrows. The &mut String won't be accessed
15181519
// until iteration is over, in Drop.
15191520
let self_ptr = self as *mut _;
1520-
// SAFETY: `assert_len` and `is_char_boundary` do the appropriate bounds checks.
1521+
// SAFETY: `slice::range` and `is_char_boundary` do the appropriate bounds checks.
15211522
let chars_iter = unsafe { self.get_unchecked(start..end) }.chars();
15221523

15231524
Drain { start, end, iter: chars_iter, string: self_ptr }

‎library/alloc/src/vec/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1597,7 +1597,7 @@ impl<T, A: Allocator> Vec<T, A> {
15971597
// the hole, and the vector length is restored to the new length.
15981598
//
15991599
let len = self.len();
1600-
let Range { start, end } = range.assert_len(len);
1600+
let Range { start, end } = slice::range(range, ..len);
16011601

16021602
unsafe {
16031603
// set self.vec length's to start, to be safe in case Drain is leaked

‎library/core/src/ops/range.rs

-90
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
use crate::fmt;
22
use crate::hash::Hash;
3-
use crate::slice::index::{
4-
slice_end_index_len_fail, slice_end_index_overflow_fail, slice_index_order_fail,
5-
slice_start_index_overflow_fail,
6-
};
73

84
/// An unbounded range (`..`).
95
///
@@ -764,92 +760,6 @@ pub trait RangeBounds<T: ?Sized> {
764760
#[stable(feature = "collections_range", since = "1.28.0")]
765761
fn end_bound(&self) -> Bound<&T>;
766762

767-
/// Performs bounds-checking of this range.
768-
///
769-
/// The returned [`Range`] is safe to pass to [`slice::get_unchecked`] and
770-
/// [`slice::get_unchecked_mut`] for slices of the given length.
771-
///
772-
/// [`slice::get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked
773-
/// [`slice::get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut
774-
///
775-
/// # Panics
776-
///
777-
/// Panics if the range would be out of bounds.
778-
///
779-
/// # Examples
780-
///
781-
/// ```
782-
/// #![feature(range_bounds_assert_len)]
783-
///
784-
/// use std::ops::RangeBounds;
785-
///
786-
/// let v = [10, 40, 30];
787-
/// assert_eq!(1..2, (1..2).assert_len(v.len()));
788-
/// assert_eq!(0..2, (..2).assert_len(v.len()));
789-
/// assert_eq!(1..3, (1..).assert_len(v.len()));
790-
/// ```
791-
///
792-
/// Panics when [`Index::index`] would panic:
793-
///
794-
/// ```should_panic
795-
/// #![feature(range_bounds_assert_len)]
796-
///
797-
/// use std::ops::RangeBounds;
798-
///
799-
/// (2..1).assert_len(3);
800-
/// ```
801-
///
802-
/// ```should_panic
803-
/// #![feature(range_bounds_assert_len)]
804-
///
805-
/// use std::ops::RangeBounds;
806-
///
807-
/// (1..4).assert_len(3);
808-
/// ```
809-
///
810-
/// ```should_panic
811-
/// #![feature(range_bounds_assert_len)]
812-
///
813-
/// use std::ops::RangeBounds;
814-
///
815-
/// (1..=usize::MAX).assert_len(3);
816-
/// ```
817-
///
818-
/// [`Index::index`]: crate::ops::Index::index
819-
#[track_caller]
820-
#[unstable(feature = "range_bounds_assert_len", issue = "76393")]
821-
fn assert_len(self, len: usize) -> Range<usize>
822-
where
823-
Self: RangeBounds<usize>,
824-
{
825-
let start: Bound<&usize> = self.start_bound();
826-
let start = match start {
827-
Bound::Included(&start) => start,
828-
Bound::Excluded(start) => {
829-
start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
830-
}
831-
Bound::Unbounded => 0,
832-
};
833-
834-
let end: Bound<&usize> = self.end_bound();
835-
let end = match end {
836-
Bound::Included(end) => {
837-
end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
838-
}
839-
Bound::Excluded(&end) => end,
840-
Bound::Unbounded => len,
841-
};
842-
843-
if start > end {
844-
slice_index_order_fail(start, end);
845-
}
846-
if end > len {
847-
slice_end_index_len_fail(end, len);
848-
}
849-
850-
Range { start, end }
851-
}
852-
853763
/// Returns `true` if `item` is contained in the range.
854764
///
855765
/// # Examples

‎library/core/src/slice/index.rs

+101-4
Original file line numberDiff line numberDiff line change
@@ -37,28 +37,28 @@ fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
3737
#[inline(never)]
3838
#[cold]
3939
#[track_caller]
40-
pub(crate) fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
40+
fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
4141
panic!("range end index {} out of range for slice of length {}", index, len);
4242
}
4343

4444
#[inline(never)]
4545
#[cold]
4646
#[track_caller]
47-
pub(crate) fn slice_index_order_fail(index: usize, end: usize) -> ! {
47+
fn slice_index_order_fail(index: usize, end: usize) -> ! {
4848
panic!("slice index starts at {} but ends at {}", index, end);
4949
}
5050

5151
#[inline(never)]
5252
#[cold]
5353
#[track_caller]
54-
pub(crate) fn slice_start_index_overflow_fail() -> ! {
54+
fn slice_start_index_overflow_fail() -> ! {
5555
panic!("attempted to index slice from after maximum usize");
5656
}
5757

5858
#[inline(never)]
5959
#[cold]
6060
#[track_caller]
61-
pub(crate) fn slice_end_index_overflow_fail() -> ! {
61+
fn slice_end_index_overflow_fail() -> ! {
6262
panic!("attempted to index slice up to maximum usize");
6363
}
6464

@@ -449,3 +449,100 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
449449
(0..=self.end).index_mut(slice)
450450
}
451451
}
452+
453+
/// Performs bounds-checking of a range.
454+
///
455+
/// This method is similar to [`Index::index`] for slices, but it returns a
456+
/// [`Range`] equivalent to `range`. You can use this method to turn any range
457+
/// into `start` and `end` values.
458+
///
459+
/// `bounds` is the range of the slice to use for bounds-checking. It should
460+
/// be a [`RangeTo`] range that ends at the length of the slice.
461+
///
462+
/// The returned [`Range`] is safe to pass to [`slice::get_unchecked`] and
463+
/// [`slice::get_unchecked_mut`] for slices with the given range.
464+
///
465+
/// [`Range`]: ops::Range
466+
/// [`RangeTo`]: ops::RangeTo
467+
/// [`slice::get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked
468+
/// [`slice::get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut
469+
///
470+
/// # Panics
471+
///
472+
/// Panics if `range` would be out of bounds.
473+
///
474+
/// # Examples
475+
///
476+
/// ```
477+
/// #![feature(slice_range)]
478+
///
479+
/// use std::slice;
480+
///
481+
/// let v = [10, 40, 30];
482+
/// assert_eq!(1..2, slice::range(1..2, ..v.len()));
483+
/// assert_eq!(0..2, slice::range(..2, ..v.len()));
484+
/// assert_eq!(1..3, slice::range(1.., ..v.len()));
485+
/// ```
486+
///
487+
/// Panics when [`Index::index`] would panic:
488+
///
489+
/// ```should_panic
490+
/// #![feature(slice_range)]
491+
///
492+
/// use std::slice;
493+
///
494+
/// slice::range(2..1, ..3);
495+
/// ```
496+
///
497+
/// ```should_panic
498+
/// #![feature(slice_range)]
499+
///
500+
/// use std::slice;
501+
///
502+
/// slice::range(1..4, ..3);
503+
/// ```
504+
///
505+
/// ```should_panic
506+
/// #![feature(slice_range)]
507+
///
508+
/// use std::slice;
509+
///
510+
/// slice::range(1..=usize::MAX, ..3);
511+
/// ```
512+
///
513+
/// [`Index::index`]: ops::Index::index
514+
#[track_caller]
515+
#[unstable(feature = "slice_range", issue = "76393")]
516+
pub fn range<R>(range: R, bounds: ops::RangeTo<usize>) -> ops::Range<usize>
517+
where
518+
R: ops::RangeBounds<usize>,
519+
{
520+
let len = bounds.end;
521+
522+
let start: ops::Bound<&usize> = range.start_bound();
523+
let start = match start {
524+
ops::Bound::Included(&start) => start,
525+
ops::Bound::Excluded(start) => {
526+
start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
527+
}
528+
ops::Bound::Unbounded => 0,
529+
};
530+
531+
let end: ops::Bound<&usize> = range.end_bound();
532+
let end = match end {
533+
ops::Bound::Included(end) => {
534+
end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
535+
}
536+
ops::Bound::Excluded(&end) => end,
537+
ops::Bound::Unbounded => len,
538+
};
539+
540+
if start > end {
541+
slice_index_order_fail(start, end);
542+
}
543+
if end > len {
544+
slice_end_index_len_fail(end, len);
545+
}
546+
547+
ops::Range { start, end }
548+
}

‎library/core/src/slice/mod.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use crate::option::Option::{None, Some};
1818
use crate::ptr;
1919
use crate::result::Result;
2020
use crate::result::Result::{Err, Ok};
21+
use crate::slice;
2122

2223
#[unstable(
2324
feature = "slice_internals",
@@ -29,7 +30,7 @@ pub mod memchr;
2930

3031
mod ascii;
3132
mod cmp;
32-
pub(crate) mod index;
33+
mod index;
3334
mod iter;
3435
mod raw;
3536
mod rotate;
@@ -76,6 +77,9 @@ pub use sort::heapsort;
7677
#[stable(feature = "slice_get_slice", since = "1.28.0")]
7778
pub use index::SliceIndex;
7879

80+
#[unstable(feature = "slice_range", issue = "76393")]
81+
pub use index::range;
82+
7983
#[lang = "slice"]
8084
#[cfg(not(test))]
8185
impl<T> [T] {
@@ -3052,7 +3056,7 @@ impl<T> [T] {
30523056
where
30533057
T: Copy,
30543058
{
3055-
let Range { start: src_start, end: src_end } = src.assert_len(self.len());
3059+
let Range { start: src_start, end: src_end } = slice::range(src, ..self.len());
30563060
let count = src_end - src_start;
30573061
assert!(dest <= self.len() - count, "dest is out of bounds");
30583062
// SAFETY: the conditions for `ptr::copy` have all been checked above,

‎src/doc/unstable-book/src/library-features/range-bounds-assert-len.md

-10
This file was deleted.

0 commit comments

Comments
 (0)
Please sign in to comment.