From 8510cf60b5e7dd2fa7695779b293d7b4722e239e Mon Sep 17 00:00:00 2001 From: Xiretza Date: Tue, 8 Nov 2022 21:27:06 +0100 Subject: [PATCH 1/8] 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/8] 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/8] 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/8] 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, &[]); /// } /// /// { From 27e681ff3516b341a8ae7e4ddba585ef6e8160b0 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Sun, 15 Jan 2023 16:22:27 +0100 Subject: [PATCH 5/8] Add from_(mut_)slice_unchecked() functions in array --- library/core/src/array/mod.rs | 51 +++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 1d067a64f900f..19575965a918c 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -774,6 +774,57 @@ impl [T; N] { } } +/// Unsafely converts a slice of `N` elements to an array reference of `N` elements. +/// +/// # Safety +/// +/// The caller must ensure that the slice has at least `N` elements. Violating this constraint +/// causes Undefined Behaviour. +/// +/// # Examples +/// +/// ``` +/// #![feature(array_from_slice)] +/// +/// let v = [1, 0, 3, 0, 5, 6]; +/// // SAFETY: `&v[2..5]` is a slice of 3 elements. +/// let r = unsafe { <&[i32; 3]>::from_slice_unchecked(&v[2..5]) }; +/// assert_eq!(r, &[3, 0, 5]); +/// ``` +#[inline] +#[must_use] +const unsafe fn from_slice_unchecked(s: &[T]) -> &[T; N] { + // SAFETY: caller guarantees that `s` is a slice of at least `N` elements. + unsafe { &*(s.as_ptr() as *const [T; N]) } +} + +/// Unsafely converts a mutable slice of `N` elements to a mutable array reference of `N` elements. +/// +/// # Safety +/// +/// The caller must ensure that the slice has at least `N` elements. Violating this constraint +/// causes Undefined Behaviour. +/// +/// # Examples +/// +/// ``` +/// #![feature(array_from_slice)] +/// +/// let mut v = [1, 0, 3, 0, 5, 6]; +/// // SAFETY: `&mut v[2..5]` is a slice of 3 elements. +/// let r = unsafe { <&mut [i32; 3]>::from_mut_slice_unchecked(&mut v[2..5]) }; +/// assert_eq!(r, &[3, 0, 5]); +/// r[1] = 9; +/// assert_eq!(r, &[3, 9, 5]); +/// assert_eq!(v, [1, 0, 3, 9, 5, 6]); +/// ``` +#[inline] +#[must_use] +const unsafe fn from_mut_slice_unchecked(s: &mut [T]) -> &mut [T; N] { + // SAFETY: caller guarantees that `s` is a slice of at least `N` elements. + unsafe { &mut *(s.as_ptr() as *mut [T; N]) } +} + /// Populate an array from the first `N` elements of `iter` /// /// # Panics From 274a7e06cd21ddd02e315ffa2ba0cc13c8cab2fb Mon Sep 17 00:00:00 2001 From: Xiretza Date: Tue, 8 Nov 2022 21:27:06 +0100 Subject: [PATCH 6/8] Return two arrays from split_array_* methods on arrays This also turns post-mono errors due to invalid indices into type errors. --- library/core/src/array/mod.rs | 72 +++++++++++++++++------------------ library/core/src/lib.rs | 1 + 2 files changed, 37 insertions(+), 36 deletions(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 19575965a918c..20d2afc8e8c8e 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -656,16 +656,16 @@ impl [T; N] { /// assert_eq!(right, &[]); /// } /// ``` - #[unstable( - feature = "split_array", - reason = "return type should have array as 2nd element", - issue = "90091" - )] + #[unstable(feature = "split_array", reason = "new API", issue = "90091")] #[inline] - 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() + pub const fn split_array_ref(&self) -> (&[T; M], &[T; N - M]) { + // SAFETY: 0 <= M <= len (N) + let (left, right) = unsafe { self.split_at_unchecked(M) }; + + // SAFETY: `split_at_unchecked()` guarantees that: + // - `left` is a slice of `M` elements, + // - `right` is a slice of `N - M` elements. + unsafe { (from_slice_unchecked(left), from_slice_unchecked(right)) } } /// Divides one mutable array reference into two at an index. @@ -687,16 +687,16 @@ impl [T; N] { /// right[1] = 4; /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); /// ``` - #[unstable( - feature = "split_array", - reason = "return type should have array as 2nd element", - issue = "90091" - )] + #[unstable(feature = "split_array", reason = "new API", issue = "90091")] #[inline] - 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() + pub const fn split_array_mut(&mut self) -> (&mut [T; M], &mut [T; N - M]) { + // SAFETY: 0 <= M <= len (N) + let (left, right) = unsafe { self.split_at_mut_unchecked(M) }; + + // SAFETY: `split_at_mut_unchecked()` guarantees that: + // - `left` is a slice of `M` elements, + // - `right` is a slice of `N - M` elements. + unsafe { (from_mut_slice_unchecked(left), from_mut_slice_unchecked(right)) } } /// Divides one array reference into two at an index from the end. @@ -730,16 +730,16 @@ impl [T; N] { /// assert_eq!(right, &[1, 2, 3, 4, 5, 6]); /// } /// ``` - #[unstable( - feature = "split_array", - reason = "return type should have array as 2nd element", - issue = "90091" - )] + #[unstable(feature = "split_array", reason = "new API", issue = "90091")] #[inline] - 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() + pub const fn rsplit_array_ref(&self) -> (&[T; N - M], &[T; M]) { + // SAFETY: 0 <= (N-M) <= len (N) + let (left, right) = unsafe { self.split_at_unchecked(N - M) }; + + // SAFETY: `split_at_unchecked()` guarantees that: + // - `left` is a slice of `N-M` elements, + // - `right` is a slice of `N - (N-M) == M` elements. + unsafe { (from_slice_unchecked(left), from_slice_unchecked(right)) } } /// Divides one mutable array reference into two at an index from the end. @@ -761,16 +761,16 @@ impl [T; N] { /// right[1] = 4; /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); /// ``` - #[unstable( - feature = "split_array", - reason = "return type should have array as 2nd element", - issue = "90091" - )] + #[unstable(feature = "split_array", reason = "new API", issue = "90091")] #[inline] - 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() + pub const fn rsplit_array_mut(&mut self) -> (&mut [T; N - M], &mut [T; M]) { + // SAFETY: 0 <= (N-M) <= len (N) + let (left, right) = unsafe { self.split_at_mut_unchecked(N - M) }; + + // SAFETY: `split_at_mut_unchecked()` guarantees that: + // - `left` is a slice of `N-M` elements, + // - `right` is a slice of `N - (N-M) == M` elements. + unsafe { (from_mut_slice_unchecked(left), from_mut_slice_unchecked(right)) } } } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 6c419eb16f3b9..0f75b2bbf458f 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -164,6 +164,7 @@ #![feature(const_waker)] #![feature(core_panic)] #![feature(duration_consts_float)] +#![feature(generic_const_exprs)] #![feature(internal_impls_macro)] #![feature(ip)] #![feature(is_ascii_octdigit)] From 3e245facd9849343c81c538c5f773a72ca28cac4 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Sun, 15 Jan 2023 16:27:21 +0100 Subject: [PATCH 7/8] core: add array::split_array() --- library/core/src/array/mod.rs | 56 ++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 20d2afc8e8c8e..8c536fd84b566 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -8,7 +8,6 @@ use crate::borrow::{Borrow, BorrowMut}; use crate::cmp::Ordering; use crate::convert::{Infallible, TryFrom}; use crate::error::Error; -use crate::fmt; use crate::hash::{self, Hash}; use crate::iter::UncheckedIterator; use crate::mem::{self, MaybeUninit}; @@ -16,6 +15,7 @@ use crate::ops::{ ChangeOutputType, ControlFlow, FromResidual, Index, IndexMut, NeverShortCircuit, Residual, Try, }; use crate::slice::{Iter, IterMut}; +use crate::{fmt, ptr}; mod ascii; mod drain; @@ -625,6 +625,60 @@ impl [T; N] { from_trusted_iterator(self.iter_mut()) } + /// Divides one array into two at an index. + /// + /// The first will contain all indices from `[0, M)` (excluding + /// the index `M` itself) and the second will contain all + /// indices from `[M, N)` (excluding the index `N` itself). + /// + /// # Examples + /// + /// ``` + /// #![feature(split_array)] + /// + /// let v = [1, 2, 3, 4, 5, 6]; + /// + /// { + /// let (left, right) = v.split_array::<0>(); + /// assert_eq!(left, []); + /// assert_eq!(right, [1, 2, 3, 4, 5, 6]); + /// } + /// + /// { + /// let (left, right) = v.split_array::<2>(); + /// assert_eq!(left, [1, 2]); + /// assert_eq!(right, [3, 4, 5, 6]); + /// } + /// + /// { + /// let (left, right) = v.split_array::<6>(); + /// assert_eq!(left, [1, 2, 3, 4, 5, 6]); + /// assert_eq!(right, []); + /// } + /// ``` + #[unstable(feature = "split_array", reason = "new API", issue = "90091")] + #[inline] + pub const fn split_array(self) -> ([T; M], [T; N - M]) { + // SAFETY: 0 <= M <= len (N) + let (left, right) = unsafe { self.split_at_unchecked(M) }; + + let left = left.as_ptr() as *const [T; M]; + let right = right.as_ptr() as *const [T; N - M]; + + // SAFETY: `left` is a valid and aligned pointer to the first `M` elements of `self` + // (guaranteed by `split_at_unchecked()`). + // `self` will be forgotten immediately after (ptr::read() cannot unwind). + let left = unsafe { ptr::read(left) }; + // SAFETY: `right` is a valid and aligned pointer to the last `N-M` elements of `self` + // (guaranteed by `split_at_unchecked()`). + // `self` will be forgotten immediately after (ptr::read() cannot unwind). + let right = unsafe { ptr::read(right) }; + + mem::forget(self); + + (left, right) + } + /// Divides one array reference into two at an index. /// /// The first will contain all indices from `[0, M)` (excluding From 07929cad3a90c4cbede776bbedec02f89a9fe6d3 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Thu, 19 Jan 2023 21:51:06 +0100 Subject: [PATCH 8/8] work around dubious const eval error --- library/core/src/intrinsics.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 23ded42fa6679..396533066accc 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2538,14 +2538,15 @@ pub(crate) fn is_aligned_and_not_null(ptr: *const T) -> bool { !ptr.is_null() && ptr.is_aligned() } +const fn max_len() -> usize { + let size = crate::mem::size_of::(); + if size == 0 { usize::MAX } else { isize::MAX as usize / size } +} + /// Checks whether an allocation of `len` instances of `T` exceeds /// the maximum allowed allocation size. pub(crate) fn is_valid_allocation_size(len: usize) -> bool { - let max_len = const { - let size = crate::mem::size_of::(); - if size == 0 { usize::MAX } else { isize::MAX as usize / size } - }; - len <= max_len + len <= max_len::() } /// Checks whether the regions of memory starting at `src` and `dst` of size