From 8510cf60b5e7dd2fa7695779b293d7b4722e239e Mon Sep 17 00:00:00 2001 From: Xiretza Date: Tue, 8 Nov 2022 21:27:06 +0100 Subject: [PATCH 1/4] Update slice::split_array_*() methods to never panic Splitting a slice returns an Option, akin to get(). --- library/core/src/array/mod.rs | 8 +-- library/core/src/slice/mod.rs | 94 +++++++++++++++++++++-------------- library/core/tests/slice.rs | 20 +++----- 3 files changed, 68 insertions(+), 54 deletions(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index bdb4c975909e0..a35a3bc5647c2 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -667,7 +667,7 @@ impl [T; N] { )] #[inline] pub fn split_array_ref(&self) -> (&[T; M], &[T]) { - (&self[..]).split_array_ref::() + (&self[..]).split_array_ref::().unwrap() } /// Divides one mutable array reference into two at an index. @@ -700,7 +700,7 @@ impl [T; N] { )] #[inline] pub fn split_array_mut(&mut self) -> (&mut [T; M], &mut [T]) { - (&mut self[..]).split_array_mut::() + (&mut self[..]).split_array_mut::().unwrap() } /// Divides one array reference into two at an index from the end. @@ -745,7 +745,7 @@ impl [T; N] { )] #[inline] pub fn rsplit_array_ref(&self) -> (&[T], &[T; M]) { - (&self[..]).rsplit_array_ref::() + (&self[..]).rsplit_array_ref::().unwrap() } /// Divides one mutable array reference into two at an index from the end. @@ -778,7 +778,7 @@ impl [T; N] { )] #[inline] pub fn rsplit_array_mut(&mut self) -> (&mut [T], &mut [T; M]) { - (&mut self[..]).rsplit_array_mut::() + (&mut self[..]).rsplit_array_mut::().unwrap() } } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 5ece1b78c0346..50fb214e1d14b 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>(); + /// 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 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 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>(); + /// 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 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 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/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 { From 1fc0dc1dc38150a8e4b9f0b4132d164a6cd46ad8 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Sun, 21 May 2023 16:16:27 +0000 Subject: [PATCH 2/4] Update array::split_array_*() methods to never panic This turns invalid split indices into post-mono errors. In the future, these will return e.g. (&[T; M], &[T; N-M]) so that an invalid index becomes a type error. --- library/core/src/array/mod.rs | 24 ++++++++---------------- library/core/tests/array.rs | 32 -------------------------------- 2 files changed, 8 insertions(+), 48 deletions(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index a35a3bc5647c2..1d0c184bd1be4 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 /// /// ``` @@ -667,6 +663,8 @@ impl [T; N] { )] #[inline] pub fn split_array_ref(&self) -> (&[T; M], &[T]) { + // FIXME: remove once constraint is encoded in return type + const { assert!(M <= N) } (&self[..]).split_array_ref::().unwrap() } @@ -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 /// /// ``` @@ -700,6 +694,8 @@ impl [T; N] { )] #[inline] pub fn split_array_mut(&mut self) -> (&mut [T; M], &mut [T]) { + // FIXME: remove once constraint is encoded in return type + const { assert!(M <= N) } (&mut self[..]).split_array_mut::().unwrap() } @@ -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 /// /// ``` @@ -745,6 +737,8 @@ impl [T; N] { )] #[inline] pub fn rsplit_array_ref(&self) -> (&[T], &[T; M]) { + // FIXME: remove once constraint is encoded in return type + const { assert!(M <= N) } (&self[..]).rsplit_array_ref::().unwrap() } @@ -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 /// /// ``` @@ -778,6 +768,8 @@ impl [T; N] { )] #[inline] pub fn rsplit_array_mut(&mut self) -> (&mut [T], &mut [T; M]) { + // FIXME: remove once constraint is encoded in return type + const { assert!(M <= N) } (&mut self[..]).rsplit_array_mut::().unwrap() } } 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; From ddbfc0ffc53d82d7f21fc03b3ba10f0821b181ae Mon Sep 17 00:00:00 2001 From: Xiretza Date: Sun, 12 Mar 2023 12:32:09 +0100 Subject: [PATCH 3/4] Make split_array_*() methods const --- library/core/src/array/mod.rs | 16 ++++++++-------- library/core/src/slice/mod.rs | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 1d0c184bd1be4..a307b20b88bcc 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -662,10 +662,10 @@ impl [T; N] { issue = "90091" )] #[inline] - pub fn split_array_ref(&self) -> (&[T; M], &[T]) { + pub const fn split_array_ref(&self) -> (&[T; M], &[T]) { // FIXME: remove once constraint is encoded in return type const { assert!(M <= N) } - (&self[..]).split_array_ref::().unwrap() + self.as_slice().split_array_ref::().unwrap() } /// Divides one mutable array reference into two at an index. @@ -693,10 +693,10 @@ impl [T; N] { issue = "90091" )] #[inline] - pub fn split_array_mut(&mut self) -> (&mut [T; M], &mut [T]) { + 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) } - (&mut self[..]).split_array_mut::().unwrap() + (self as &mut [T]).split_array_mut::().unwrap() } /// Divides one array reference into two at an index from the end. @@ -736,10 +736,10 @@ impl [T; N] { issue = "90091" )] #[inline] - pub fn rsplit_array_ref(&self) -> (&[T], &[T; M]) { + pub const fn rsplit_array_ref(&self) -> (&[T], &[T; M]) { // FIXME: remove once constraint is encoded in return type const { assert!(M <= N) } - (&self[..]).rsplit_array_ref::().unwrap() + self.as_slice().rsplit_array_ref::().unwrap() } /// Divides one mutable array reference into two at an index from the end. @@ -767,10 +767,10 @@ impl [T; N] { issue = "90091" )] #[inline] - pub fn rsplit_array_mut(&mut self) -> (&mut [T], &mut [T; M]) { + 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) } - (&mut self[..]).rsplit_array_mut::().unwrap() + (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 50fb214e1d14b..9c3d9bba442e8 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1797,7 +1797,7 @@ impl [T] { #[inline] #[track_caller] #[must_use] - pub fn split_array_ref(&self) -> Option<(&[T; N], &[T])> { + pub const fn split_array_ref(&self) -> Option<(&[T; N], &[T])> { if N > self.len() { None } else { @@ -1835,7 +1835,7 @@ impl [T] { #[inline] #[track_caller] #[must_use] - pub fn split_array_mut(&mut self) -> Option<(&mut [T; N], &mut [T])> { + pub const fn split_array_mut(&mut self) -> Option<(&mut [T; N], &mut [T])> { if N > self.len() { None } else { @@ -1885,7 +1885,7 @@ impl [T] { #[unstable(feature = "split_array", reason = "new API", issue = "90091")] #[inline] #[must_use] - pub fn rsplit_array_ref(&self) -> Option<(&[T], &[T; N])> { + pub const fn rsplit_array_ref(&self) -> Option<(&[T], &[T; N])> { if N > self.len() { None } else { @@ -1923,7 +1923,7 @@ impl [T] { #[unstable(feature = "split_array", reason = "new API", issue = "90091")] #[inline] #[must_use] - pub fn rsplit_array_mut(&mut self) -> Option<(&mut [T], &mut [T; N])> { + pub const fn rsplit_array_mut(&mut self) -> Option<(&mut [T], &mut [T; N])> { if N > self.len() { None } else { From 34356dbf595c180371192ba7b21eb46c83f2dee5 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Sun, 21 May 2023 17:11:18 +0000 Subject: [PATCH 4/4] core: fix indentation in split_array doc comments --- library/core/src/array/mod.rs | 12 ++++++------ library/core/src/slice/mod.rs | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index a307b20b88bcc..1d067a64f900f 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -639,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]); /// } /// /// { @@ -713,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, &[]); /// } /// /// { diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 9c3d9bba442e8..2952bc763a1cb 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1774,9 +1774,9 @@ impl [T] { /// let v = &[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::<0>().unwrap(); + /// assert_eq!(left, &[]); + /// assert_eq!(right, [1, 2, 3, 4, 5, 6]); /// } /// /// { @@ -1863,9 +1863,9 @@ impl [T] { /// let v = &[1, 2, 3, 4, 5, 6][..]; /// /// { - /// 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::<0>().unwrap(); + /// assert_eq!(left, [1, 2, 3, 4, 5, 6]); + /// assert_eq!(right, &[]); /// } /// /// {