From 9d29793614cc810fb8febf7f1a2e0202f3919bb6 Mon Sep 17 00:00:00 2001 From: dylni <46035563+dylni@users.noreply.github.com> Date: Sun, 17 Jan 2021 23:12:29 -0500 Subject: [PATCH 1/5] Improve design of `assert_len` --- .../alloc/src/collections/vec_deque/mod.rs | 2 +- library/alloc/src/lib.rs | 2 +- library/alloc/src/string.rs | 4 +-- library/alloc/src/vec/mod.rs | 2 +- library/core/src/ops/range.rs | 35 ++++++++++++------- library/core/src/slice/mod.rs | 2 +- .../range-bounds-assert-len.md | 10 ------ .../range-bounds-ensure-subset-of.md | 10 ++++++ 8 files changed, 38 insertions(+), 29 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/range-bounds-assert-len.md create mode 100644 src/doc/unstable-book/src/library-features/range-bounds-ensure-subset-of.md diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index eb8994681937a..0c267cbc106b9 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1063,7 +1063,7 @@ impl VecDeque { where R: RangeBounds, { - let Range { start, end } = range.assert_len(self.len()); + let Range { start, end } = range.ensure_subset_of(..self.len()); let tail = self.wrap_add(self.tail, start); let head = self.wrap_add(self.tail, end); (tail, head) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 99c42a4ba4423..71b4883aca284 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -115,7 +115,7 @@ #![feature(or_patterns)] #![feature(pattern)] #![feature(ptr_internals)] -#![feature(range_bounds_assert_len)] +#![feature(range_bounds_ensure_subset_of)] #![feature(rustc_attrs)] #![feature(receiver_trait)] #![cfg_attr(bootstrap, feature(min_const_generics))] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 3218b3535c970..3ab5ca4f566ad 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1510,14 +1510,14 @@ impl String { // of the vector version. The data is just plain bytes. // Because the range removal happens in Drop, if the Drain iterator is leaked, // the removal will not happen. - let Range { start, end } = range.assert_len(self.len()); + let Range { start, end } = range.ensure_subset_of(..self.len()); assert!(self.is_char_boundary(start)); assert!(self.is_char_boundary(end)); // Take out two simultaneous borrows. The &mut String won't be accessed // until iteration is over, in Drop. let self_ptr = self as *mut _; - // SAFETY: `assert_len` and `is_char_boundary` do the appropriate bounds checks. + // SAFETY: `ensure_subset_of` and `is_char_boundary` do the appropriate bounds checks. let chars_iter = unsafe { self.get_unchecked(start..end) }.chars(); Drain { start, end, iter: chars_iter, string: self_ptr } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index b40c1a8c57aa4..5c20f382224c1 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1650,7 +1650,7 @@ impl Vec { // the hole, and the vector length is restored to the new length. // let len = self.len(); - let Range { start, end } = range.assert_len(len); + let Range { start, end } = range.ensure_subset_of(..len); unsafe { // set self.vec length's to start, to be safe in case Drain is leaked diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 0571dc74b9af9..7a0dd5a8f0f72 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -766,8 +766,15 @@ pub trait RangeBounds { /// Performs bounds-checking of this range. /// + /// This method is similar to [`Index::index`] for slices, but it returns a + /// [`Range`] equivalent to this range. You can use this method to turn any + /// range into `start` and `end` values. + /// + /// The given range is the range of the slice to use for bounds-checking. It + /// should be a [`RangeTo`] range that ends at the length of the slice. + /// /// The returned [`Range`] is safe to pass to [`slice::get_unchecked`] and - /// [`slice::get_unchecked_mut`] for slices of the given length. + /// [`slice::get_unchecked_mut`] for slices with the given range. /// /// [`slice::get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked /// [`slice::get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut @@ -779,49 +786,51 @@ pub trait RangeBounds { /// # Examples /// /// ``` - /// #![feature(range_bounds_assert_len)] + /// #![feature(range_bounds_ensure_subset_of)] /// /// use std::ops::RangeBounds; /// /// let v = [10, 40, 30]; - /// assert_eq!(1..2, (1..2).assert_len(v.len())); - /// assert_eq!(0..2, (..2).assert_len(v.len())); - /// assert_eq!(1..3, (1..).assert_len(v.len())); + /// assert_eq!(1..2, (1..2).ensure_subset_of(..v.len())); + /// assert_eq!(0..2, (..2).ensure_subset_of(..v.len())); + /// assert_eq!(1..3, (1..).ensure_subset_of(..v.len())); /// ``` /// /// Panics when [`Index::index`] would panic: /// /// ```should_panic - /// #![feature(range_bounds_assert_len)] + /// #![feature(range_bounds_ensure_subset_of)] /// /// use std::ops::RangeBounds; /// - /// (2..1).assert_len(3); + /// (2..1).ensure_subset_of(..3); /// ``` /// /// ```should_panic - /// #![feature(range_bounds_assert_len)] + /// #![feature(range_bounds_ensure_subset_of)] /// /// use std::ops::RangeBounds; /// - /// (1..4).assert_len(3); + /// (1..4).ensure_subset_of(..3); /// ``` /// /// ```should_panic - /// #![feature(range_bounds_assert_len)] + /// #![feature(range_bounds_ensure_subset_of)] /// /// use std::ops::RangeBounds; /// - /// (1..=usize::MAX).assert_len(3); + /// (1..=usize::MAX).ensure_subset_of(..3); /// ``` /// /// [`Index::index`]: crate::ops::Index::index #[track_caller] - #[unstable(feature = "range_bounds_assert_len", issue = "76393")] - fn assert_len(self, len: usize) -> Range + #[unstable(feature = "range_bounds_ensure_subset_of", issue = "76393")] + fn ensure_subset_of(self, range: RangeTo) -> Range where Self: RangeBounds, { + let len = range.end; + let start: Bound<&usize> = self.start_bound(); let start = match start { Bound::Included(&start) => start, diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 19a3b45e568c0..90351be69291e 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3052,7 +3052,7 @@ impl [T] { where T: Copy, { - let Range { start: src_start, end: src_end } = src.assert_len(self.len()); + let Range { start: src_start, end: src_end } = src.ensure_subset_of(..self.len()); let count = src_end - src_start; assert!(dest <= self.len() - count, "dest is out of bounds"); // SAFETY: the conditions for `ptr::copy` have all been checked above, diff --git a/src/doc/unstable-book/src/library-features/range-bounds-assert-len.md b/src/doc/unstable-book/src/library-features/range-bounds-assert-len.md deleted file mode 100644 index 0e95d5ded9296..0000000000000 --- a/src/doc/unstable-book/src/library-features/range-bounds-assert-len.md +++ /dev/null @@ -1,10 +0,0 @@ -# `range_bounds_assert_len` - -The tracking issue for this feature is: [#76393] - ------------------------- - -This adds [`RangeBounds::assert_len`]. - -[#76393]: https://github.com/rust-lang/rust/issues/76393 -[`RangeBounds::assert_len`]: https://doc.rust-lang.org/nightly/std/ops/trait.RangeBounds.html#method.assert_len diff --git a/src/doc/unstable-book/src/library-features/range-bounds-ensure-subset-of.md b/src/doc/unstable-book/src/library-features/range-bounds-ensure-subset-of.md new file mode 100644 index 0000000000000..ea3f01ff5f9d1 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/range-bounds-ensure-subset-of.md @@ -0,0 +1,10 @@ +# `range_bounds_ensure_subset_of` + +The tracking issue for this feature is: [#76393] + +------------------------ + +This adds [`RangeBounds::ensure_subset_of`]. + +[#76393]: https://github.com/rust-lang/rust/issues/76393 +[`RangeBounds::ensure_subset_of`]: https://doc.rust-lang.org/nightly/std/ops/trait.RangeBounds.html#method.ensure_subset_of From cb647f3e8e32180cde0f0e7a2599a5dc5b35345a Mon Sep 17 00:00:00 2001 From: dylni <46035563+dylni@users.noreply.github.com> Date: Mon, 18 Jan 2021 09:22:17 -0500 Subject: [PATCH 2/5] Fix possible soundness issue in `ensure_subset_of` --- .../alloc/src/collections/vec_deque/mod.rs | 2 +- library/alloc/src/lib.rs | 2 +- library/alloc/src/string.rs | 2 +- library/alloc/src/vec/mod.rs | 2 +- library/core/src/ops/range.rs | 192 +++++++++--------- library/core/src/slice/mod.rs | 2 +- .../range-bounds-ensure-subset-of.md | 10 - .../range-ensure-subset-of.md | 10 + 8 files changed, 112 insertions(+), 110 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/range-bounds-ensure-subset-of.md create mode 100644 src/doc/unstable-book/src/library-features/range-ensure-subset-of.md diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 0c267cbc106b9..319ca666fc622 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1063,7 +1063,7 @@ impl VecDeque { where R: RangeBounds, { - let Range { start, end } = range.ensure_subset_of(..self.len()); + let Range { start, end } = Range::ensure_subset_of(range, ..self.len()); let tail = self.wrap_add(self.tail, start); let head = self.wrap_add(self.tail, end); (tail, head) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 71b4883aca284..ade2e3fed2c2d 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -115,7 +115,7 @@ #![feature(or_patterns)] #![feature(pattern)] #![feature(ptr_internals)] -#![feature(range_bounds_ensure_subset_of)] +#![feature(range_ensure_subset_of)] #![feature(rustc_attrs)] #![feature(receiver_trait)] #![cfg_attr(bootstrap, feature(min_const_generics))] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 3ab5ca4f566ad..ef2f264ec7ea8 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -1510,7 +1510,7 @@ impl String { // of the vector version. The data is just plain bytes. // Because the range removal happens in Drop, if the Drain iterator is leaked, // the removal will not happen. - let Range { start, end } = range.ensure_subset_of(..self.len()); + let Range { start, end } = Range::ensure_subset_of(range, ..self.len()); assert!(self.is_char_boundary(start)); assert!(self.is_char_boundary(end)); diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 5c20f382224c1..1a7b846bd8514 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1650,7 +1650,7 @@ impl Vec { // the hole, and the vector length is restored to the new length. // let len = self.len(); - let Range { start, end } = range.ensure_subset_of(..len); + let Range { start, end } = Range::ensure_subset_of(range, ..len); unsafe { // set self.vec length's to start, to be safe in case Drain is leaked diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 7a0dd5a8f0f72..b30ff9450ff02 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -151,6 +151,103 @@ impl> Range { } } +impl Range { + /// Performs bounds-checking of a range. + /// + /// This method is similar to [`Index::index`] for slices, but it returns a + /// `Range` equivalent to `range`. You can use this method to turn any range + /// into `start` and `end` values. + /// + /// `bounds` is the range of the slice to use for bounds-checking. It should + /// be a [`RangeTo`] range that ends at the length of the slice. + /// + /// The returned `Range` is safe to pass to [`slice::get_unchecked`] and + /// [`slice::get_unchecked_mut`] for slices with the given range. + /// + /// [`slice::get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked + /// [`slice::get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut + /// + /// # Panics + /// + /// Panics if `range` would be out of bounds. + /// + /// # Examples + /// + /// ``` + /// #![feature(range_ensure_subset_of)] + /// + /// use std::ops::Range; + /// + /// let v = [10, 40, 30]; + /// assert_eq!(1..2, Range::ensure_subset_of(1..2, ..v.len())); + /// assert_eq!(0..2, Range::ensure_subset_of(..2, ..v.len())); + /// assert_eq!(1..3, Range::ensure_subset_of(1.., ..v.len())); + /// ``` + /// + /// Panics when [`Index::index`] would panic: + /// + /// ```should_panic + /// #![feature(range_ensure_subset_of)] + /// + /// use std::ops::Range; + /// + /// Range::ensure_subset_of(2..1, ..3); + /// ``` + /// + /// ```should_panic + /// #![feature(range_ensure_subset_of)] + /// + /// use std::ops::Range; + /// + /// Range::ensure_subset_of(1..4, ..3); + /// ``` + /// + /// ```should_panic + /// #![feature(range_ensure_subset_of)] + /// + /// use std::ops::Range; + /// + /// Range::ensure_subset_of(1..=usize::MAX, ..3); + /// ``` + /// + /// [`Index::index`]: crate::ops::Index::index + #[track_caller] + #[unstable(feature = "range_ensure_subset_of", issue = "76393")] + pub fn ensure_subset_of(range: R, bounds: RangeTo) -> Self + where + R: RangeBounds, + { + let len = bounds.end; + + let start: Bound<&usize> = range.start_bound(); + let start = match start { + Bound::Included(&start) => start, + Bound::Excluded(start) => { + start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) + } + Bound::Unbounded => 0, + }; + + let end: Bound<&usize> = range.end_bound(); + let end = match end { + Bound::Included(end) => { + end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) + } + Bound::Excluded(&end) => end, + Bound::Unbounded => len, + }; + + if start > end { + slice_index_order_fail(start, end); + } + if end > len { + slice_end_index_len_fail(end, len); + } + + Self { start, end } + } +} + /// A range only bounded inclusively below (`start..`). /// /// The `RangeFrom` `start..` contains all values with `x >= start`. @@ -764,101 +861,6 @@ pub trait RangeBounds { #[stable(feature = "collections_range", since = "1.28.0")] fn end_bound(&self) -> Bound<&T>; - /// Performs bounds-checking of this range. - /// - /// This method is similar to [`Index::index`] for slices, but it returns a - /// [`Range`] equivalent to this range. You can use this method to turn any - /// range into `start` and `end` values. - /// - /// The given range is the range of the slice to use for bounds-checking. It - /// should be a [`RangeTo`] range that ends at the length of the slice. - /// - /// The returned [`Range`] is safe to pass to [`slice::get_unchecked`] and - /// [`slice::get_unchecked_mut`] for slices with the given range. - /// - /// [`slice::get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked - /// [`slice::get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut - /// - /// # Panics - /// - /// Panics if the range would be out of bounds. - /// - /// # Examples - /// - /// ``` - /// #![feature(range_bounds_ensure_subset_of)] - /// - /// use std::ops::RangeBounds; - /// - /// let v = [10, 40, 30]; - /// assert_eq!(1..2, (1..2).ensure_subset_of(..v.len())); - /// assert_eq!(0..2, (..2).ensure_subset_of(..v.len())); - /// assert_eq!(1..3, (1..).ensure_subset_of(..v.len())); - /// ``` - /// - /// Panics when [`Index::index`] would panic: - /// - /// ```should_panic - /// #![feature(range_bounds_ensure_subset_of)] - /// - /// use std::ops::RangeBounds; - /// - /// (2..1).ensure_subset_of(..3); - /// ``` - /// - /// ```should_panic - /// #![feature(range_bounds_ensure_subset_of)] - /// - /// use std::ops::RangeBounds; - /// - /// (1..4).ensure_subset_of(..3); - /// ``` - /// - /// ```should_panic - /// #![feature(range_bounds_ensure_subset_of)] - /// - /// use std::ops::RangeBounds; - /// - /// (1..=usize::MAX).ensure_subset_of(..3); - /// ``` - /// - /// [`Index::index`]: crate::ops::Index::index - #[track_caller] - #[unstable(feature = "range_bounds_ensure_subset_of", issue = "76393")] - fn ensure_subset_of(self, range: RangeTo) -> Range - where - Self: RangeBounds, - { - let len = range.end; - - let start: Bound<&usize> = self.start_bound(); - let start = match start { - Bound::Included(&start) => start, - Bound::Excluded(start) => { - start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) - } - Bound::Unbounded => 0, - }; - - let end: Bound<&usize> = self.end_bound(); - let end = match end { - Bound::Included(end) => { - end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) - } - Bound::Excluded(&end) => end, - Bound::Unbounded => len, - }; - - if start > end { - slice_index_order_fail(start, end); - } - if end > len { - slice_end_index_len_fail(end, len); - } - - Range { start, end } - } - /// Returns `true` if `item` is contained in the range. /// /// # Examples diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 90351be69291e..e78b647651101 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3052,7 +3052,7 @@ impl [T] { where T: Copy, { - let Range { start: src_start, end: src_end } = src.ensure_subset_of(..self.len()); + let Range { start: src_start, end: src_end } = Range::ensure_subset_of(src, ..self.len()); let count = src_end - src_start; assert!(dest <= self.len() - count, "dest is out of bounds"); // SAFETY: the conditions for `ptr::copy` have all been checked above, diff --git a/src/doc/unstable-book/src/library-features/range-bounds-ensure-subset-of.md b/src/doc/unstable-book/src/library-features/range-bounds-ensure-subset-of.md deleted file mode 100644 index ea3f01ff5f9d1..0000000000000 --- a/src/doc/unstable-book/src/library-features/range-bounds-ensure-subset-of.md +++ /dev/null @@ -1,10 +0,0 @@ -# `range_bounds_ensure_subset_of` - -The tracking issue for this feature is: [#76393] - ------------------------- - -This adds [`RangeBounds::ensure_subset_of`]. - -[#76393]: https://github.com/rust-lang/rust/issues/76393 -[`RangeBounds::ensure_subset_of`]: https://doc.rust-lang.org/nightly/std/ops/trait.RangeBounds.html#method.ensure_subset_of diff --git a/src/doc/unstable-book/src/library-features/range-ensure-subset-of.md b/src/doc/unstable-book/src/library-features/range-ensure-subset-of.md new file mode 100644 index 0000000000000..8b5a21a34cfbb --- /dev/null +++ b/src/doc/unstable-book/src/library-features/range-ensure-subset-of.md @@ -0,0 +1,10 @@ +# `range_ensure_subset_of` + +The tracking issue for this feature is: [#76393] + +------------------------ + +This adds [`Range::ensure_subset_of`]. + +[#76393]: https://github.com/rust-lang/rust/issues/76393 +[`Range::ensure_subset_of`]: https://doc.rust-lang.org/std/ops/struct.Range.html#method.ensure_subset_of From f6111a256e94855f18f36f02930f8b0ae0012542 Mon Sep 17 00:00:00 2001 From: dylni <46035563+dylni@users.noreply.github.com> Date: Mon, 18 Jan 2021 14:48:22 -0500 Subject: [PATCH 3/5] Remove unnecessary documentation page --- .../src/library-features/range-ensure-subset-of.md | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/range-ensure-subset-of.md diff --git a/src/doc/unstable-book/src/library-features/range-ensure-subset-of.md b/src/doc/unstable-book/src/library-features/range-ensure-subset-of.md deleted file mode 100644 index 8b5a21a34cfbb..0000000000000 --- a/src/doc/unstable-book/src/library-features/range-ensure-subset-of.md +++ /dev/null @@ -1,10 +0,0 @@ -# `range_ensure_subset_of` - -The tracking issue for this feature is: [#76393] - ------------------------- - -This adds [`Range::ensure_subset_of`]. - -[#76393]: https://github.com/rust-lang/rust/issues/76393 -[`Range::ensure_subset_of`]: https://doc.rust-lang.org/std/ops/struct.Range.html#method.ensure_subset_of From 5d519eaa6e9a583257b2f9e28a743ab85d1cabc5 Mon Sep 17 00:00:00 2001 From: dylni <46035563+dylni@users.noreply.github.com> Date: Mon, 1 Feb 2021 21:20:44 -0500 Subject: [PATCH 4/5] Rename `Range::ensure_subset_of` to `slice::range` --- .../alloc/src/collections/vec_deque/mod.rs | 2 +- library/alloc/src/lib.rs | 2 +- library/alloc/src/slice.rs | 2 + library/alloc/src/string.rs | 5 +- library/alloc/src/vec/mod.rs | 2 +- library/core/src/ops/range.rs | 101 ----------------- library/core/src/slice/index.rs | 105 +++++++++++++++++- library/core/src/slice/mod.rs | 8 +- 8 files changed, 115 insertions(+), 112 deletions(-) diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 319ca666fc622..f7cefdce27856 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1063,7 +1063,7 @@ impl VecDeque { where R: RangeBounds, { - let Range { start, end } = Range::ensure_subset_of(range, ..self.len()); + let Range { start, end } = slice::range(range, ..self.len()); let tail = self.wrap_add(self.tail, start); let head = self.wrap_add(self.tail, end); (tail, head) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index ade2e3fed2c2d..c020a969f1fb9 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -115,7 +115,6 @@ #![feature(or_patterns)] #![feature(pattern)] #![feature(ptr_internals)] -#![feature(range_ensure_subset_of)] #![feature(rustc_attrs)] #![feature(receiver_trait)] #![cfg_attr(bootstrap, feature(min_const_generics))] @@ -123,6 +122,7 @@ #![feature(set_ptr_value)] #![feature(slice_ptr_get)] #![feature(slice_ptr_len)] +#![feature(slice_range)] #![feature(staged_api)] #![feature(str_internals)] #![feature(trusted_len)] diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index cb015b949305c..c5ffade12619f 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -92,6 +92,8 @@ use crate::borrow::ToOwned; use crate::boxed::Box; use crate::vec::Vec; +#[unstable(feature = "slice_range", issue = "76393")] +pub use core::slice::range; #[unstable(feature = "array_chunks", issue = "74985")] pub use core::slice::ArrayChunks; #[unstable(feature = "array_chunks", issue = "74985")] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index ef2f264ec7ea8..b4deedc52638c 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -49,6 +49,7 @@ use core::iter::{FromIterator, FusedIterator}; use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds}; use core::ptr; +use core::slice; use core::str::{lossy, pattern::Pattern}; use crate::borrow::{Cow, ToOwned}; @@ -1510,14 +1511,14 @@ impl String { // of the vector version. The data is just plain bytes. // Because the range removal happens in Drop, if the Drain iterator is leaked, // the removal will not happen. - let Range { start, end } = Range::ensure_subset_of(range, ..self.len()); + let Range { start, end } = slice::range(range, ..self.len()); assert!(self.is_char_boundary(start)); assert!(self.is_char_boundary(end)); // Take out two simultaneous borrows. The &mut String won't be accessed // until iteration is over, in Drop. let self_ptr = self as *mut _; - // SAFETY: `ensure_subset_of` and `is_char_boundary` do the appropriate bounds checks. + // SAFETY: `slice::range` and `is_char_boundary` do the appropriate bounds checks. let chars_iter = unsafe { self.get_unchecked(start..end) }.chars(); Drain { start, end, iter: chars_iter, string: self_ptr } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 1a7b846bd8514..a8474f8ca5921 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1650,7 +1650,7 @@ impl Vec { // the hole, and the vector length is restored to the new length. // let len = self.len(); - let Range { start, end } = Range::ensure_subset_of(range, ..len); + let Range { start, end } = slice::range(range, ..len); unsafe { // set self.vec length's to start, to be safe in case Drain is leaked diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index b30ff9450ff02..dbeb391213006 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -1,9 +1,5 @@ use crate::fmt; use crate::hash::Hash; -use crate::slice::index::{ - slice_end_index_len_fail, slice_end_index_overflow_fail, slice_index_order_fail, - slice_start_index_overflow_fail, -}; /// An unbounded range (`..`). /// @@ -151,103 +147,6 @@ impl> Range { } } -impl Range { - /// Performs bounds-checking of a range. - /// - /// This method is similar to [`Index::index`] for slices, but it returns a - /// `Range` equivalent to `range`. You can use this method to turn any range - /// into `start` and `end` values. - /// - /// `bounds` is the range of the slice to use for bounds-checking. It should - /// be a [`RangeTo`] range that ends at the length of the slice. - /// - /// The returned `Range` is safe to pass to [`slice::get_unchecked`] and - /// [`slice::get_unchecked_mut`] for slices with the given range. - /// - /// [`slice::get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked - /// [`slice::get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut - /// - /// # Panics - /// - /// Panics if `range` would be out of bounds. - /// - /// # Examples - /// - /// ``` - /// #![feature(range_ensure_subset_of)] - /// - /// use std::ops::Range; - /// - /// let v = [10, 40, 30]; - /// assert_eq!(1..2, Range::ensure_subset_of(1..2, ..v.len())); - /// assert_eq!(0..2, Range::ensure_subset_of(..2, ..v.len())); - /// assert_eq!(1..3, Range::ensure_subset_of(1.., ..v.len())); - /// ``` - /// - /// Panics when [`Index::index`] would panic: - /// - /// ```should_panic - /// #![feature(range_ensure_subset_of)] - /// - /// use std::ops::Range; - /// - /// Range::ensure_subset_of(2..1, ..3); - /// ``` - /// - /// ```should_panic - /// #![feature(range_ensure_subset_of)] - /// - /// use std::ops::Range; - /// - /// Range::ensure_subset_of(1..4, ..3); - /// ``` - /// - /// ```should_panic - /// #![feature(range_ensure_subset_of)] - /// - /// use std::ops::Range; - /// - /// Range::ensure_subset_of(1..=usize::MAX, ..3); - /// ``` - /// - /// [`Index::index`]: crate::ops::Index::index - #[track_caller] - #[unstable(feature = "range_ensure_subset_of", issue = "76393")] - pub fn ensure_subset_of(range: R, bounds: RangeTo) -> Self - where - R: RangeBounds, - { - let len = bounds.end; - - let start: Bound<&usize> = range.start_bound(); - let start = match start { - Bound::Included(&start) => start, - Bound::Excluded(start) => { - start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) - } - Bound::Unbounded => 0, - }; - - let end: Bound<&usize> = range.end_bound(); - let end = match end { - Bound::Included(end) => { - end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) - } - Bound::Excluded(&end) => end, - Bound::Unbounded => len, - }; - - if start > end { - slice_index_order_fail(start, end); - } - if end > len { - slice_end_index_len_fail(end, len); - } - - Self { start, end } - } -} - /// A range only bounded inclusively below (`start..`). /// /// The `RangeFrom` `start..` contains all values with `x >= start`. diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 660c8a2da5da0..d20986bb724fc 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -37,28 +37,28 @@ fn slice_start_index_len_fail(index: usize, len: usize) -> ! { #[inline(never)] #[cold] #[track_caller] -pub(crate) fn slice_end_index_len_fail(index: usize, len: usize) -> ! { +fn slice_end_index_len_fail(index: usize, len: usize) -> ! { panic!("range end index {} out of range for slice of length {}", index, len); } #[inline(never)] #[cold] #[track_caller] -pub(crate) fn slice_index_order_fail(index: usize, end: usize) -> ! { +fn slice_index_order_fail(index: usize, end: usize) -> ! { panic!("slice index starts at {} but ends at {}", index, end); } #[inline(never)] #[cold] #[track_caller] -pub(crate) fn slice_start_index_overflow_fail() -> ! { +fn slice_start_index_overflow_fail() -> ! { panic!("attempted to index slice from after maximum usize"); } #[inline(never)] #[cold] #[track_caller] -pub(crate) fn slice_end_index_overflow_fail() -> ! { +fn slice_end_index_overflow_fail() -> ! { panic!("attempted to index slice up to maximum usize"); } @@ -449,3 +449,100 @@ unsafe impl SliceIndex<[T]> for ops::RangeToInclusive { (0..=self.end).index_mut(slice) } } + +/// Performs bounds-checking of a range. +/// +/// This method is similar to [`Index::index`] for slices, but it returns a +/// [`Range`] equivalent to `range`. You can use this method to turn any range +/// into `start` and `end` values. +/// +/// `bounds` is the range of the slice to use for bounds-checking. It should +/// be a [`RangeTo`] range that ends at the length of the slice. +/// +/// The returned [`Range`] is safe to pass to [`slice::get_unchecked`] and +/// [`slice::get_unchecked_mut`] for slices with the given range. +/// +/// [`Range`]: ops::Range +/// [`RangeTo`]: ops::RangeTo +/// [`slice::get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked +/// [`slice::get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut +/// +/// # Panics +/// +/// Panics if `range` would be out of bounds. +/// +/// # Examples +/// +/// ``` +/// #![feature(slice_range)] +/// +/// use std::slice; +/// +/// let v = [10, 40, 30]; +/// assert_eq!(1..2, slice::range(1..2, ..v.len())); +/// assert_eq!(0..2, slice::range(..2, ..v.len())); +/// assert_eq!(1..3, slice::range(1.., ..v.len())); +/// ``` +/// +/// Panics when [`Index::index`] would panic: +/// +/// ```should_panic +/// #![feature(slice_range)] +/// +/// use std::slice; +/// +/// slice::range(2..1, ..3); +/// ``` +/// +/// ```should_panic +/// #![feature(slice_range)] +/// +/// use std::slice; +/// +/// slice::range(1..4, ..3); +/// ``` +/// +/// ```should_panic +/// #![feature(slice_range)] +/// +/// use std::slice; +/// +/// slice::range(1..=usize::MAX, ..3); +/// ``` +/// +/// [`Index::index`]: ops::Index::index +#[track_caller] +#[unstable(feature = "slice_range", issue = "76393")] +pub fn range(range: R, bounds: ops::RangeTo) -> ops::Range +where + R: ops::RangeBounds, +{ + let len = bounds.end; + + let start: ops::Bound<&usize> = range.start_bound(); + let start = match start { + ops::Bound::Included(&start) => start, + ops::Bound::Excluded(start) => { + start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) + } + ops::Bound::Unbounded => 0, + }; + + let end: ops::Bound<&usize> = range.end_bound(); + let end = match end { + ops::Bound::Included(end) => { + end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) + } + ops::Bound::Excluded(&end) => end, + ops::Bound::Unbounded => len, + }; + + if start > end { + slice_index_order_fail(start, end); + } + if end > len { + slice_end_index_len_fail(end, len); + } + + ops::Range { start, end } +} diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index e78b647651101..8256d2cc6070e 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -18,6 +18,7 @@ use crate::option::Option::{None, Some}; use crate::ptr; use crate::result::Result; use crate::result::Result::{Err, Ok}; +use crate::slice; #[unstable( feature = "slice_internals", @@ -29,7 +30,7 @@ pub mod memchr; mod ascii; mod cmp; -pub(crate) mod index; +mod index; mod iter; mod raw; mod rotate; @@ -76,6 +77,9 @@ pub use sort::heapsort; #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use index::SliceIndex; +#[unstable(feature = "slice_range", issue = "76393")] +pub use index::range; + #[lang = "slice"] #[cfg(not(test))] impl [T] { @@ -3052,7 +3056,7 @@ impl [T] { where T: Copy, { - let Range { start: src_start, end: src_end } = Range::ensure_subset_of(src, ..self.len()); + let Range { start: src_start, end: src_end } = slice::range(src, ..self.len()); let count = src_end - src_start; assert!(dest <= self.len() - count, "dest is out of bounds"); // SAFETY: the conditions for `ptr::copy` have all been checked above, From fe4fe19ddc38a2da883e1e38d18c821ad1c26fc5 Mon Sep 17 00:00:00 2001 From: dylni <46035563+dylni@users.noreply.github.com> Date: Fri, 12 Feb 2021 22:03:39 -0500 Subject: [PATCH 5/5] Update new usage of `assert_len` --- library/alloc/src/vec/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index a8474f8ca5921..77302d33bc187 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2036,11 +2036,11 @@ impl Vec { where R: RangeBounds, { - let range = src.assert_len(self.len()); + let range = slice::range(src, ..self.len()); self.reserve(range.len()); // SAFETY: - // - `assert_len` guarantees that the given range is valid for indexing self + // - `slice::range` guarantees that the given range is valid for indexing self unsafe { self.spec_extend_from_within(range); }