Skip to content

Commit 301a4f2

Browse files
authored
Rollup merge of rust-lang#83233 - jethrogb:split_array, r=yaahc
Implement split_array and split_array_mut This implements `[T]::split_array::<const N>() -> (&[T; N], &[T])` and `[T; N]::split_array::<const M>() -> (&[T; M], &[T])` and their mutable equivalents. These are another few “missing” array implementations now that const generics are a thing, similar to rust-lang#74373, rust-lang#75026, etc. Fixes rust-lang#74674. This implements `[T; N]::split_array` returning an array and a slice. Ultimately, this is probably not what we want, we would want the second return value to be an array of length N-M, which will likely be possible with future const generics enhancements. We need to implement the array method now though, to immediately shadow the slice method. This way, when the slice methods get stabilized, calling them on an array will not be automatic through coercion, so we won't have trouble stabilizing the array methods later (cf. into_iter debacle). An unchecked version of `[T]::split_array` could also be added as in rust-lang#76014. This would not be needed for `[T; N]::split_array` as that can be compile-time checked. Edit: actually, since split_at_unchecked is internal-only it could be changed to be split_array-only.
2 parents 45b600c + 4a43976 commit 301a4f2

File tree

5 files changed

+219
-0
lines changed

5 files changed

+219
-0
lines changed

library/core/src/array/mod.rs

+78
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,84 @@ impl<T, const N: usize> [T; N] {
500500
// items.
501501
unsafe { collect_into_array_unchecked(&mut self.iter_mut()) }
502502
}
503+
504+
/// Divides one array reference into two at an index.
505+
///
506+
/// The first will contain all indices from `[0, M)` (excluding
507+
/// the index `M` itself) and the second will contain all
508+
/// indices from `[M, N)` (excluding the index `N` itself).
509+
///
510+
/// # Panics
511+
///
512+
/// Panics if `M > N`.
513+
///
514+
/// # Examples
515+
///
516+
/// ```
517+
/// #![feature(split_array)]
518+
///
519+
/// let v = [1, 2, 3, 4, 5, 6];
520+
///
521+
/// {
522+
/// let (left, right) = v.split_array_ref::<0>();
523+
/// assert_eq!(left, &[]);
524+
/// assert_eq!(right, &[1, 2, 3, 4, 5, 6]);
525+
/// }
526+
///
527+
/// {
528+
/// let (left, right) = v.split_array_ref::<2>();
529+
/// assert_eq!(left, &[1, 2]);
530+
/// assert_eq!(right, &[3, 4, 5, 6]);
531+
/// }
532+
///
533+
/// {
534+
/// let (left, right) = v.split_array_ref::<6>();
535+
/// assert_eq!(left, &[1, 2, 3, 4, 5, 6]);
536+
/// assert_eq!(right, &[]);
537+
/// }
538+
/// ```
539+
#[unstable(
540+
feature = "split_array",
541+
reason = "return type should have array as 2nd element",
542+
issue = "90091"
543+
)]
544+
#[inline]
545+
pub fn split_array_ref<const M: usize>(&self) -> (&[T; M], &[T]) {
546+
(&self[..]).split_array_ref::<M>()
547+
}
548+
549+
/// Divides one mutable array reference into two at an index.
550+
///
551+
/// The first will contain all indices from `[0, M)` (excluding
552+
/// the index `M` itself) and the second will contain all
553+
/// indices from `[M, N)` (excluding the index `N` itself).
554+
///
555+
/// # Panics
556+
///
557+
/// Panics if `M > N`.
558+
///
559+
/// # Examples
560+
///
561+
/// ```
562+
/// #![feature(split_array)]
563+
///
564+
/// let mut v = [1, 0, 3, 0, 5, 6];
565+
/// let (left, right) = v.split_array_mut::<2>();
566+
/// assert_eq!(left, &mut [1, 0][..]);
567+
/// assert_eq!(right, &mut [3, 0, 5, 6]);
568+
/// left[1] = 2;
569+
/// right[1] = 4;
570+
/// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
571+
/// ```
572+
#[unstable(
573+
feature = "split_array",
574+
reason = "return type should have array as 2nd element",
575+
issue = "90091"
576+
)]
577+
#[inline]
578+
pub fn split_array_mut<const M: usize>(&mut self) -> (&mut [T; M], &mut [T]) {
579+
(&mut self[..]).split_array_mut::<M>()
580+
}
503581
}
504582

505583
/// Pulls `N` items from `iter` and returns them as an array. If the iterator

library/core/src/slice/mod.rs

+74
Original file line numberDiff line numberDiff line change
@@ -1665,6 +1665,80 @@ impl<T> [T] {
16651665
unsafe { (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid)) }
16661666
}
16671667

1668+
/// Divides one slice into an array and a remainder slice at an index.
1669+
///
1670+
/// The array will contain all indices from `[0, N)` (excluding
1671+
/// the index `N` itself) and the slice will contain all
1672+
/// indices from `[N, len)` (excluding the index `len` itself).
1673+
///
1674+
/// # Panics
1675+
///
1676+
/// Panics if `N > len`.
1677+
///
1678+
/// # Examples
1679+
///
1680+
/// ```
1681+
/// #![feature(split_array)]
1682+
///
1683+
/// let v = &[1, 2, 3, 4, 5, 6][..];
1684+
///
1685+
/// {
1686+
/// let (left, right) = v.split_array_ref::<0>();
1687+
/// assert_eq!(left, &[]);
1688+
/// assert_eq!(right, [1, 2, 3, 4, 5, 6]);
1689+
/// }
1690+
///
1691+
/// {
1692+
/// let (left, right) = v.split_array_ref::<2>();
1693+
/// assert_eq!(left, &[1, 2]);
1694+
/// assert_eq!(right, [3, 4, 5, 6]);
1695+
/// }
1696+
///
1697+
/// {
1698+
/// let (left, right) = v.split_array_ref::<6>();
1699+
/// assert_eq!(left, &[1, 2, 3, 4, 5, 6]);
1700+
/// assert_eq!(right, []);
1701+
/// }
1702+
/// ```
1703+
#[unstable(feature = "split_array", reason = "new API", issue = "90091")]
1704+
#[inline]
1705+
pub fn split_array_ref<const N: usize>(&self) -> (&[T; N], &[T]) {
1706+
let (a, b) = self.split_at(N);
1707+
// SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at)
1708+
unsafe { (&*(a.as_ptr() as *const [T; N]), b) }
1709+
}
1710+
1711+
/// Divides one mutable slice into an array and a remainder slice at an index.
1712+
///
1713+
/// The array will contain all indices from `[0, N)` (excluding
1714+
/// the index `N` itself) and the slice will contain all
1715+
/// indices from `[N, len)` (excluding the index `len` itself).
1716+
///
1717+
/// # Panics
1718+
///
1719+
/// Panics if `N > len`.
1720+
///
1721+
/// # Examples
1722+
///
1723+
/// ```
1724+
/// #![feature(split_array)]
1725+
///
1726+
/// let mut v = &mut [1, 0, 3, 0, 5, 6][..];
1727+
/// let (left, right) = v.split_array_mut::<2>();
1728+
/// assert_eq!(left, &mut [1, 0]);
1729+
/// assert_eq!(right, [3, 0, 5, 6]);
1730+
/// left[1] = 2;
1731+
/// right[1] = 4;
1732+
/// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
1733+
/// ```
1734+
#[unstable(feature = "split_array", reason = "new API", issue = "90091")]
1735+
#[inline]
1736+
pub fn split_array_mut<const N: usize>(&mut self) -> (&mut [T; N], &mut [T]) {
1737+
let (a, b) = self.split_at_mut(N);
1738+
// SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at_mut)
1739+
unsafe { (&mut *(a.as_mut_ptr() as *mut [T; N]), b) }
1740+
}
1741+
16681742
/// Returns an iterator over subslices separated by elements that match
16691743
/// `pred`. The matched element is not contained in the subslices.
16701744
///

library/core/tests/array.rs

+33
Original file line numberDiff line numberDiff line change
@@ -436,3 +436,36 @@ where
436436
std::panic::set_hook(prev_hook);
437437
result
438438
}
439+
440+
#[test]
441+
fn array_split_array_mut() {
442+
let mut v = [1, 2, 3, 4, 5, 6];
443+
444+
{
445+
let (left, right) = v.split_array_mut::<0>();
446+
assert_eq!(left, &mut []);
447+
assert_eq!(right, &mut [1, 2, 3, 4, 5, 6]);
448+
}
449+
450+
{
451+
let (left, right) = v.split_array_mut::<6>();
452+
assert_eq!(left, &mut [1, 2, 3, 4, 5, 6]);
453+
assert_eq!(right, &mut []);
454+
}
455+
}
456+
457+
#[should_panic]
458+
#[test]
459+
fn array_split_array_ref_out_of_bounds() {
460+
let v = [1, 2, 3, 4, 5, 6];
461+
462+
v.split_array_ref::<7>();
463+
}
464+
465+
#[should_panic]
466+
#[test]
467+
fn array_split_array_mut_out_of_bounds() {
468+
let mut v = [1, 2, 3, 4, 5, 6];
469+
470+
v.split_array_mut::<7>();
471+
}

library/core/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
#![feature(integer_atomics)]
7171
#![feature(int_roundings)]
7272
#![feature(slice_group_by)]
73+
#![feature(split_array)]
7374
#![feature(trusted_random_access)]
7475
#![feature(unsize)]
7576
#![feature(unzip_option)]

library/core/tests/slice.rs

+33
Original file line numberDiff line numberDiff line change
@@ -2191,3 +2191,36 @@ mod swap_panics {
21912191
x.swap(2, 5);
21922192
}
21932193
}
2194+
2195+
#[test]
2196+
fn slice_split_array_mut() {
2197+
let v = &mut [1, 2, 3, 4, 5, 6][..];
2198+
2199+
{
2200+
let (left, right) = v.split_array_mut::<0>();
2201+
assert_eq!(left, &mut []);
2202+
assert_eq!(right, [1, 2, 3, 4, 5, 6]);
2203+
}
2204+
2205+
{
2206+
let (left, right) = v.split_array_mut::<6>();
2207+
assert_eq!(left, &mut [1, 2, 3, 4, 5, 6]);
2208+
assert_eq!(right, []);
2209+
}
2210+
}
2211+
2212+
#[should_panic]
2213+
#[test]
2214+
fn slice_split_array_ref_out_of_bounds() {
2215+
let v = &[1, 2, 3, 4, 5, 6][..];
2216+
2217+
v.split_array_ref::<7>();
2218+
}
2219+
2220+
#[should_panic]
2221+
#[test]
2222+
fn slice_split_array_mut_out_of_bounds() {
2223+
let v = &mut [1, 2, 3, 4, 5, 6][..];
2224+
2225+
v.split_array_mut::<7>();
2226+
}

0 commit comments

Comments
 (0)