diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index bdb4c975909e0..1d067a64f900f 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -631,10 +631,6 @@ impl [T; N] { /// the index `M` itself) and the second will contain all /// indices from `[M, N)` (excluding the index `N` itself). /// - /// # Panics - /// - /// Panics if `M > N`. - /// /// # Examples /// /// ``` @@ -643,9 +639,9 @@ impl [T; N] { /// let v = [1, 2, 3, 4, 5, 6]; /// /// { - /// let (left, right) = v.split_array_ref::<0>(); - /// assert_eq!(left, &[]); - /// assert_eq!(right, &[1, 2, 3, 4, 5, 6]); + /// let (left, right) = v.split_array_ref::<0>(); + /// assert_eq!(left, &[]); + /// assert_eq!(right, &[1, 2, 3, 4, 5, 6]); /// } /// /// { @@ -666,8 +662,10 @@ impl [T; N] { issue = "90091" )] #[inline] - pub fn split_array_ref(&self) -> (&[T; M], &[T]) { - (&self[..]).split_array_ref::() + pub const fn split_array_ref(&self) -> (&[T; M], &[T]) { + // FIXME: remove once constraint is encoded in return type + const { assert!(M <= N) } + self.as_slice().split_array_ref::().unwrap() } /// Divides one mutable array reference into two at an index. @@ -676,10 +674,6 @@ impl [T; N] { /// the index `M` itself) and the second will contain all /// indices from `[M, N)` (excluding the index `N` itself). /// - /// # Panics - /// - /// Panics if `M > N`. - /// /// # Examples /// /// ``` @@ -699,8 +693,10 @@ impl [T; N] { issue = "90091" )] #[inline] - pub fn split_array_mut(&mut self) -> (&mut [T; M], &mut [T]) { - (&mut self[..]).split_array_mut::() + pub const fn split_array_mut(&mut self) -> (&mut [T; M], &mut [T]) { + // FIXME: remove once constraint is encoded in return type + const { assert!(M <= N) } + (self as &mut [T]).split_array_mut::().unwrap() } /// Divides one array reference into two at an index from the end. @@ -709,10 +705,6 @@ impl [T; N] { /// the index `N - M` itself) and the second will contain all /// indices from `[N - M, N)` (excluding the index `N` itself). /// - /// # Panics - /// - /// Panics if `M > N`. - /// /// # Examples /// /// ``` @@ -721,9 +713,9 @@ impl [T; N] { /// let v = [1, 2, 3, 4, 5, 6]; /// /// { - /// let (left, right) = v.rsplit_array_ref::<0>(); - /// assert_eq!(left, &[1, 2, 3, 4, 5, 6]); - /// assert_eq!(right, &[]); + /// let (left, right) = v.rsplit_array_ref::<0>(); + /// assert_eq!(left, &[1, 2, 3, 4, 5, 6]); + /// assert_eq!(right, &[]); /// } /// /// { @@ -744,8 +736,10 @@ impl [T; N] { issue = "90091" )] #[inline] - pub fn rsplit_array_ref(&self) -> (&[T], &[T; M]) { - (&self[..]).rsplit_array_ref::() + pub const fn rsplit_array_ref(&self) -> (&[T], &[T; M]) { + // FIXME: remove once constraint is encoded in return type + const { assert!(M <= N) } + self.as_slice().rsplit_array_ref::().unwrap() } /// Divides one mutable array reference into two at an index from the end. @@ -754,10 +748,6 @@ impl [T; N] { /// the index `N - M` itself) and the second will contain all /// indices from `[N - M, N)` (excluding the index `N` itself). /// - /// # Panics - /// - /// Panics if `M > N`. - /// /// # Examples /// /// ``` @@ -777,8 +767,10 @@ impl [T; N] { issue = "90091" )] #[inline] - pub fn rsplit_array_mut(&mut self) -> (&mut [T], &mut [T; M]) { - (&mut self[..]).rsplit_array_mut::() + pub const fn rsplit_array_mut(&mut self) -> (&mut [T], &mut [T; M]) { + // FIXME: remove once constraint is encoded in return type + const { assert!(M <= N) } + (self as &mut [T]).rsplit_array_mut::().unwrap() } } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 5ece1b78c0346..2952bc763a1cb 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1764,9 +1764,7 @@ impl [T] { /// the index `N` itself) and the slice will contain all /// indices from `[N, len)` (excluding the index `len` itself). /// - /// # Panics - /// - /// Panics if `N > len`. + /// Returns `None` if the slice has less than `N` elements. /// /// # Examples /// @@ -1776,31 +1774,38 @@ impl [T] { /// let v = &[1, 2, 3, 4, 5, 6][..]; /// /// { - /// let (left, right) = v.split_array_ref::<0>(); - /// assert_eq!(left, &[]); - /// assert_eq!(right, [1, 2, 3, 4, 5, 6]); + /// let (left, right) = v.split_array_ref::<0>().unwrap(); + /// assert_eq!(left, &[]); + /// assert_eq!(right, [1, 2, 3, 4, 5, 6]); /// } /// /// { - /// let (left, right) = v.split_array_ref::<2>(); + /// let (left, right) = v.split_array_ref::<2>().unwrap(); /// assert_eq!(left, &[1, 2]); /// assert_eq!(right, [3, 4, 5, 6]); /// } /// /// { - /// let (left, right) = v.split_array_ref::<6>(); + /// let (left, right) = v.split_array_ref::<6>().unwrap(); /// assert_eq!(left, &[1, 2, 3, 4, 5, 6]); /// assert_eq!(right, []); /// } + /// + /// assert!(v.split_array_ref::<7>().is_none()); /// ``` #[unstable(feature = "split_array", reason = "new API", issue = "90091")] #[inline] #[track_caller] #[must_use] - pub fn split_array_ref(&self) -> (&[T; N], &[T]) { - let (a, b) = self.split_at(N); - // SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at) - unsafe { (&*(a.as_ptr() as *const [T; N]), b) } + pub const fn split_array_ref(&self) -> Option<(&[T; N], &[T])> { + if N > self.len() { + None + } else { + // SAFETY: 0 <= N <= len + let (a, b) = unsafe { self.split_at_unchecked(N) }; + // SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at) + Some(unsafe { (&*(a.as_ptr() as *const [T; N]), b) }) + } } /// Divides one mutable slice into an array and a remainder slice at an index. @@ -1809,9 +1814,7 @@ impl [T] { /// the index `N` itself) and the slice will contain all /// indices from `[N, len)` (excluding the index `len` itself). /// - /// # Panics - /// - /// Panics if `N > len`. + /// Returns `None` if the slice has less than `N` elements. /// /// # Examples /// @@ -1819,21 +1822,28 @@ impl [T] { /// #![feature(split_array)] /// /// let mut v = &mut [1, 0, 3, 0, 5, 6][..]; - /// let (left, right) = v.split_array_mut::<2>(); + /// let (left, right) = v.split_array_mut::<2>().unwrap(); /// assert_eq!(left, &mut [1, 0]); /// assert_eq!(right, [3, 0, 5, 6]); /// left[1] = 2; /// right[1] = 4; /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); + /// + /// assert!(v.split_array_mut::<7>().is_none()); /// ``` #[unstable(feature = "split_array", reason = "new API", issue = "90091")] #[inline] #[track_caller] #[must_use] - pub fn split_array_mut(&mut self) -> (&mut [T; N], &mut [T]) { - let (a, b) = self.split_at_mut(N); - // SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at_mut) - unsafe { (&mut *(a.as_mut_ptr() as *mut [T; N]), b) } + pub const fn split_array_mut(&mut self) -> Option<(&mut [T; N], &mut [T])> { + if N > self.len() { + None + } else { + // SAFETY: 0 <= N <= len + let (a, b) = unsafe { self.split_at_mut_unchecked(N) }; + // SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at) + Some(unsafe { (&mut *(a.as_mut_ptr() as *mut [T; N]), b) }) + } } /// Divides one slice into an array and a remainder slice at an index from @@ -1843,9 +1853,7 @@ impl [T] { /// the index `len - N` itself) and the array will contain all /// indices from `[len - N, len)` (excluding the index `len` itself). /// - /// # Panics - /// - /// Panics if `N > len`. + /// Returns `None` if the slice has less than `N` elements. /// /// # Examples /// @@ -1855,31 +1863,37 @@ impl [T] { /// let v = &[1, 2, 3, 4, 5, 6][..]; /// /// { - /// let (left, right) = v.rsplit_array_ref::<0>(); - /// assert_eq!(left, [1, 2, 3, 4, 5, 6]); - /// assert_eq!(right, &[]); + /// let (left, right) = v.rsplit_array_ref::<0>().unwrap(); + /// assert_eq!(left, [1, 2, 3, 4, 5, 6]); + /// assert_eq!(right, &[]); /// } /// /// { - /// let (left, right) = v.rsplit_array_ref::<2>(); + /// let (left, right) = v.rsplit_array_ref::<2>().unwrap(); /// assert_eq!(left, [1, 2, 3, 4]); /// assert_eq!(right, &[5, 6]); /// } /// /// { - /// let (left, right) = v.rsplit_array_ref::<6>(); + /// let (left, right) = v.rsplit_array_ref::<6>().unwrap(); /// assert_eq!(left, []); /// assert_eq!(right, &[1, 2, 3, 4, 5, 6]); /// } + /// + /// assert!(v.rsplit_array_ref::<7>().is_none()); /// ``` #[unstable(feature = "split_array", reason = "new API", issue = "90091")] #[inline] #[must_use] - pub fn rsplit_array_ref(&self) -> (&[T], &[T; N]) { - assert!(N <= self.len()); - let (a, b) = self.split_at(self.len() - N); - // SAFETY: b points to [T; N]? Yes it's [T] of length N (checked by split_at) - unsafe { (a, &*(b.as_ptr() as *const [T; N])) } + pub const fn rsplit_array_ref(&self) -> Option<(&[T], &[T; N])> { + if N > self.len() { + None + } else { + // SAFETY: N <= len; thus 0 <= len - N <= len + let (a, b) = unsafe { self.split_at_unchecked(self.len() - N) }; + // SAFETY: b points to [T; N]? Yes it's [T] of length N (checked by split_at) + Some(unsafe { (a, &*(b.as_ptr() as *const [T; N])) }) + } } /// Divides one mutable slice into an array and a remainder slice at an @@ -1889,9 +1903,7 @@ impl [T] { /// the index `N` itself) and the array will contain all /// indices from `[len - N, len)` (excluding the index `len` itself). /// - /// # Panics - /// - /// Panics if `N > len`. + /// Returns `None` if the slice has less than `N` elements. /// /// # Examples /// @@ -1899,21 +1911,27 @@ impl [T] { /// #![feature(split_array)] /// /// let mut v = &mut [1, 0, 3, 0, 5, 6][..]; - /// let (left, right) = v.rsplit_array_mut::<4>(); + /// let (left, right) = v.rsplit_array_mut::<4>().unwrap(); /// assert_eq!(left, [1, 0]); /// assert_eq!(right, &mut [3, 0, 5, 6]); /// left[1] = 2; /// right[1] = 4; /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); + /// + /// assert!(v.rsplit_array_mut::<7>().is_none()); /// ``` #[unstable(feature = "split_array", reason = "new API", issue = "90091")] #[inline] #[must_use] - pub fn rsplit_array_mut(&mut self) -> (&mut [T], &mut [T; N]) { - assert!(N <= self.len()); - let (a, b) = self.split_at_mut(self.len() - N); - // SAFETY: b points to [T; N]? Yes it's [T] of length N (checked by split_at_mut) - unsafe { (a, &mut *(b.as_mut_ptr() as *mut [T; N])) } + pub const fn rsplit_array_mut(&mut self) -> Option<(&mut [T], &mut [T; N])> { + if N > self.len() { + None + } else { + // SAFETY: N <= len; thus 0 <= len - N <= len + let (a, b) = unsafe { self.split_at_mut_unchecked(self.len() - N) }; + // SAFETY: b points to [T; N]? Yes it's [T] of length N (checked by split_at_mut) + Some(unsafe { (a, &mut *(b.as_mut_ptr() as *mut [T; N])) }) + } } /// Returns an iterator over subslices separated by elements that match diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs index 0869644c040f5..da834921ad257 100644 --- a/library/core/tests/array.rs +++ b/library/core/tests/array.rs @@ -488,38 +488,6 @@ fn array_rsplit_array_mut() { } } -#[should_panic] -#[test] -fn array_split_array_ref_out_of_bounds() { - let v = [1, 2, 3, 4, 5, 6]; - - v.split_array_ref::<7>(); -} - -#[should_panic] -#[test] -fn array_split_array_mut_out_of_bounds() { - let mut v = [1, 2, 3, 4, 5, 6]; - - v.split_array_mut::<7>(); -} - -#[should_panic] -#[test] -fn array_rsplit_array_ref_out_of_bounds() { - let v = [1, 2, 3, 4, 5, 6]; - - v.rsplit_array_ref::<7>(); -} - -#[should_panic] -#[test] -fn array_rsplit_array_mut_out_of_bounds() { - let mut v = [1, 2, 3, 4, 5, 6]; - - v.rsplit_array_mut::<7>(); -} - #[test] fn array_intoiter_advance_by() { use std::cell::Cell; diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 88f54591bb4a4..381e9304c2c7b 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -2375,13 +2375,13 @@ fn slice_split_array_mut() { let v = &mut [1, 2, 3, 4, 5, 6][..]; { - let (left, right) = v.split_array_mut::<0>(); + let (left, right) = v.split_array_mut::<0>().unwrap(); assert_eq!(left, &mut []); assert_eq!(right, [1, 2, 3, 4, 5, 6]); } { - let (left, right) = v.split_array_mut::<6>(); + let (left, right) = v.split_array_mut::<6>().unwrap(); assert_eq!(left, &mut [1, 2, 3, 4, 5, 6]); assert_eq!(right, []); } @@ -2392,13 +2392,13 @@ fn slice_rsplit_array_mut() { let v = &mut [1, 2, 3, 4, 5, 6][..]; { - let (left, right) = v.rsplit_array_mut::<0>(); + let (left, right) = v.rsplit_array_mut::<0>().unwrap(); assert_eq!(left, [1, 2, 3, 4, 5, 6]); assert_eq!(right, &mut []); } { - let (left, right) = v.rsplit_array_mut::<6>(); + let (left, right) = v.rsplit_array_mut::<6>().unwrap(); assert_eq!(left, []); assert_eq!(right, &mut [1, 2, 3, 4, 5, 6]); } @@ -2416,36 +2416,32 @@ fn split_as_slice() { assert_eq!(split.as_slice(), &[]); } -#[should_panic] #[test] fn slice_split_array_ref_out_of_bounds() { let v = &[1, 2, 3, 4, 5, 6][..]; - let _ = v.split_array_ref::<7>(); + assert!(v.split_array_ref::<7>().is_none()); } -#[should_panic] #[test] fn slice_split_array_mut_out_of_bounds() { let v = &mut [1, 2, 3, 4, 5, 6][..]; - let _ = v.split_array_mut::<7>(); + assert!(v.split_array_mut::<7>().is_none()); } -#[should_panic] #[test] fn slice_rsplit_array_ref_out_of_bounds() { let v = &[1, 2, 3, 4, 5, 6][..]; - let _ = v.rsplit_array_ref::<7>(); + assert!(v.rsplit_array_ref::<7>().is_none()); } -#[should_panic] #[test] fn slice_rsplit_array_mut_out_of_bounds() { let v = &mut [1, 2, 3, 4, 5, 6][..]; - let _ = v.rsplit_array_mut::<7>(); + assert!(v.rsplit_array_mut::<7>().is_none()); } macro_rules! take_tests {