Skip to content

Commit 755cfbf

Browse files
committed
core: introduce split_at{,_mut}_checked
Introduce split_at_checked and split_at_mut_checked methods to slices types (including str) which are non-panicking versions of split_at and split_at_mut respectively. This is analogous to get method being non-panicking version of indexing.
1 parent 227abac commit 755cfbf

File tree

3 files changed

+375
-28
lines changed

3 files changed

+375
-28
lines changed

library/core/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@
184184
#![feature(set_ptr_value)]
185185
#![feature(slice_ptr_get)]
186186
#![feature(slice_split_at_unchecked)]
187+
#![feature(split_at_checked)]
187188
#![feature(str_internals)]
188189
#![feature(str_split_inclusive_remainder)]
189190
#![feature(str_split_remainder)]

library/core/src/slice/mod.rs

+263-10
Original file line numberDiff line numberDiff line change
@@ -1842,7 +1842,8 @@ impl<T> [T] {
18421842
///
18431843
/// # Panics
18441844
///
1845-
/// Panics if `mid > len`.
1845+
/// Panics if `mid > len`. For a non-panicking alternative see
1846+
/// [`split_at_checked`](slice::split_at_checked).
18461847
///
18471848
/// # Examples
18481849
///
@@ -1869,14 +1870,15 @@ impl<T> [T] {
18691870
/// ```
18701871
#[stable(feature = "rust1", since = "1.0.0")]
18711872
#[rustc_const_stable(feature = "const_slice_split_at_not_mut", since = "1.71.0")]
1873+
#[rustc_allow_const_fn_unstable(split_at_checked)]
18721874
#[inline]
18731875
#[track_caller]
18741876
#[must_use]
18751877
pub const fn split_at(&self, mid: usize) -> (&[T], &[T]) {
1876-
assert!(mid <= self.len());
1877-
// SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which
1878-
// fulfills the requirements of `split_at_unchecked`.
1879-
unsafe { self.split_at_unchecked(mid) }
1878+
match self.split_at_checked(mid) {
1879+
Some(pair) => pair,
1880+
None => panic!("mid > len"),
1881+
}
18801882
}
18811883

18821884
/// Divides one mutable slice into two at an index.
@@ -1887,7 +1889,8 @@ impl<T> [T] {
18871889
///
18881890
/// # Panics
18891891
///
1890-
/// Panics if `mid > len`.
1892+
/// Panics if `mid > len`. For a non-panicking alternative see
1893+
/// [`split_at_mut_checked`](slice::split_at_mut_checked).
18911894
///
18921895
/// # Examples
18931896
///
@@ -1906,10 +1909,10 @@ impl<T> [T] {
19061909
#[must_use]
19071910
#[rustc_const_unstable(feature = "const_slice_split_at_mut", issue = "101804")]
19081911
pub const fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
1909-
assert!(mid <= self.len());
1910-
// SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which
1911-
// fulfills the requirements of `from_raw_parts_mut`.
1912-
unsafe { self.split_at_mut_unchecked(mid) }
1912+
match self.split_at_mut_checked(mid) {
1913+
Some(pair) => pair,
1914+
None => panic!("mid > len"),
1915+
}
19131916
}
19141917

19151918
/// Divides one slice into two at an index, without doing bounds checking.
@@ -2031,6 +2034,256 @@ impl<T> [T] {
20312034
unsafe { (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid)) }
20322035
}
20332036

2037+
/// Divides one slice into two at an index returning, `None` if slice is too
2038+
/// short.
2039+
///
2040+
/// The first will contain all indices from `[0, mid)` (excluding
2041+
/// the index `mid` itself) and the second will contain all
2042+
/// indices from `[mid, len)` (excluding the index `len` itself).
2043+
///
2044+
/// Returns `None` if `mid > len`.
2045+
///
2046+
/// # Examples
2047+
///
2048+
/// ```
2049+
/// #![feature(split_at_checked)]
2050+
///
2051+
/// let v = [1, 2, 3, 4, 5, 6];
2052+
///
2053+
/// {
2054+
/// let (left, right) = v.split_at_checked(0).unwrap();
2055+
/// assert_eq!(left, []);
2056+
/// assert_eq!(right, [1, 2, 3, 4, 5, 6]);
2057+
/// }
2058+
///
2059+
/// {
2060+
/// let (left, right) = v.split_at_checked(2).unwrap();
2061+
/// assert_eq!(left, [1, 2]);
2062+
/// assert_eq!(right, [3, 4, 5, 6]);
2063+
/// }
2064+
///
2065+
/// {
2066+
/// let (left, right) = v.split_at_checked(6).unwrap();
2067+
/// assert_eq!(left, [1, 2, 3, 4, 5, 6]);
2068+
/// assert_eq!(right, []);
2069+
/// }
2070+
///
2071+
/// assert_eq!(None, v.split_at_checked(7));
2072+
/// ```
2073+
#[unstable(feature = "split_at_checked", reason = "new API", issue = "119128")]
2074+
#[rustc_const_unstable(feature = "split_at_checked", issue = "119128")]
2075+
#[inline]
2076+
#[track_caller]
2077+
#[must_use]
2078+
pub const fn split_at_checked(&self, mid: usize) -> Option<(&[T], &[T])> {
2079+
if mid <= self.len() {
2080+
// SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which
2081+
// fulfills the requirements of `split_at_unchecked`.
2082+
Some(unsafe { self.split_at_unchecked(mid) })
2083+
} else {
2084+
None
2085+
}
2086+
}
2087+
2088+
/// Divides one mutable slice into two at an index, returning `None` if
2089+
/// slice is too short.
2090+
///
2091+
/// The first will contain all indices from `[0, mid)` (excluding
2092+
/// the index `mid` itself) and the second will contain all
2093+
/// indices from `[mid, len)` (excluding the index `len` itself).
2094+
///
2095+
/// Returns `None` if `mid > len`.
2096+
///
2097+
/// # Examples
2098+
///
2099+
/// ```
2100+
/// #![feature(split_at_checked)]
2101+
///
2102+
/// let mut v = [1, 0, 3, 0, 5, 6];
2103+
///
2104+
/// if let Some((left, right)) = v.split_at_mut_checked(2) {
2105+
/// assert_eq!(left, [1, 0]);
2106+
/// assert_eq!(right, [3, 0, 5, 6]);
2107+
/// left[1] = 2;
2108+
/// right[1] = 4;
2109+
/// }
2110+
/// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
2111+
///
2112+
/// assert_eq!(None, v.split_at_mut_checked(7));
2113+
/// ```
2114+
#[unstable(feature = "split_at_checked", reason = "new API", issue = "119128")]
2115+
#[rustc_const_unstable(feature = "split_at_checked", issue = "119128")]
2116+
#[inline]
2117+
#[track_caller]
2118+
#[must_use]
2119+
pub const fn split_at_mut_checked(&mut self, mid: usize) -> Option<(&mut [T], &mut [T])> {
2120+
if mid <= self.len() {
2121+
// SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which
2122+
// fulfills the requirements of `split_at_unchecked`.
2123+
Some(unsafe { self.split_at_mut_unchecked(mid) })
2124+
} else {
2125+
None
2126+
}
2127+
}
2128+
2129+
/// Divides one slice into an array and a remainder slice at an index.
2130+
///
2131+
/// The array will contain all indices from `[0, N)` (excluding
2132+
/// the index `N` itself) and the slice will contain all
2133+
/// indices from `[N, len)` (excluding the index `len` itself).
2134+
///
2135+
/// # Panics
2136+
///
2137+
/// Panics if `N > len`.
2138+
///
2139+
/// # Examples
2140+
///
2141+
/// ```
2142+
/// #![feature(split_array)]
2143+
///
2144+
/// let v = &[1, 2, 3, 4, 5, 6][..];
2145+
///
2146+
/// {
2147+
/// let (left, right) = v.split_array_ref::<0>();
2148+
/// assert_eq!(left, &[]);
2149+
/// assert_eq!(right, [1, 2, 3, 4, 5, 6]);
2150+
/// }
2151+
///
2152+
/// {
2153+
/// let (left, right) = v.split_array_ref::<2>();
2154+
/// assert_eq!(left, &[1, 2]);
2155+
/// assert_eq!(right, [3, 4, 5, 6]);
2156+
/// }
2157+
///
2158+
/// {
2159+
/// let (left, right) = v.split_array_ref::<6>();
2160+
/// assert_eq!(left, &[1, 2, 3, 4, 5, 6]);
2161+
/// assert_eq!(right, []);
2162+
/// }
2163+
/// ```
2164+
#[unstable(feature = "split_array", reason = "new API", issue = "90091")]
2165+
#[inline]
2166+
#[track_caller]
2167+
#[must_use]
2168+
pub fn split_array_ref<const N: usize>(&self) -> (&[T; N], &[T]) {
2169+
let (a, b) = self.split_at(N);
2170+
// SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at)
2171+
unsafe { (&*(a.as_ptr() as *const [T; N]), b) }
2172+
}
2173+
2174+
/// Divides one mutable slice into an array and a remainder slice at an index.
2175+
///
2176+
/// The array will contain all indices from `[0, N)` (excluding
2177+
/// the index `N` itself) and the slice will contain all
2178+
/// indices from `[N, len)` (excluding the index `len` itself).
2179+
///
2180+
/// # Panics
2181+
///
2182+
/// Panics if `N > len`.
2183+
///
2184+
/// # Examples
2185+
///
2186+
/// ```
2187+
/// #![feature(split_array)]
2188+
///
2189+
/// let mut v = &mut [1, 0, 3, 0, 5, 6][..];
2190+
/// let (left, right) = v.split_array_mut::<2>();
2191+
/// assert_eq!(left, &mut [1, 0]);
2192+
/// assert_eq!(right, [3, 0, 5, 6]);
2193+
/// left[1] = 2;
2194+
/// right[1] = 4;
2195+
/// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
2196+
/// ```
2197+
#[unstable(feature = "split_array", reason = "new API", issue = "90091")]
2198+
#[inline]
2199+
#[track_caller]
2200+
#[must_use]
2201+
pub fn split_array_mut<const N: usize>(&mut self) -> (&mut [T; N], &mut [T]) {
2202+
let (a, b) = self.split_at_mut(N);
2203+
// SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at_mut)
2204+
unsafe { (&mut *(a.as_mut_ptr() as *mut [T; N]), b) }
2205+
}
2206+
2207+
/// Divides one slice into an array and a remainder slice at an index from
2208+
/// the end.
2209+
///
2210+
/// The slice will contain all indices from `[0, len - N)` (excluding
2211+
/// the index `len - N` itself) and the array will contain all
2212+
/// indices from `[len - N, len)` (excluding the index `len` itself).
2213+
///
2214+
/// # Panics
2215+
///
2216+
/// Panics if `N > len`.
2217+
///
2218+
/// # Examples
2219+
///
2220+
/// ```
2221+
/// #![feature(split_array)]
2222+
///
2223+
/// let v = &[1, 2, 3, 4, 5, 6][..];
2224+
///
2225+
/// {
2226+
/// let (left, right) = v.rsplit_array_ref::<0>();
2227+
/// assert_eq!(left, [1, 2, 3, 4, 5, 6]);
2228+
/// assert_eq!(right, &[]);
2229+
/// }
2230+
///
2231+
/// {
2232+
/// let (left, right) = v.rsplit_array_ref::<2>();
2233+
/// assert_eq!(left, [1, 2, 3, 4]);
2234+
/// assert_eq!(right, &[5, 6]);
2235+
/// }
2236+
///
2237+
/// {
2238+
/// let (left, right) = v.rsplit_array_ref::<6>();
2239+
/// assert_eq!(left, []);
2240+
/// assert_eq!(right, &[1, 2, 3, 4, 5, 6]);
2241+
/// }
2242+
/// ```
2243+
#[unstable(feature = "split_array", reason = "new API", issue = "90091")]
2244+
#[inline]
2245+
#[must_use]
2246+
pub fn rsplit_array_ref<const N: usize>(&self) -> (&[T], &[T; N]) {
2247+
assert!(N <= self.len());
2248+
let (a, b) = self.split_at(self.len() - N);
2249+
// SAFETY: b points to [T; N]? Yes it's [T] of length N (checked by split_at)
2250+
unsafe { (a, &*(b.as_ptr() as *const [T; N])) }
2251+
}
2252+
2253+
/// Divides one mutable slice into an array and a remainder slice at an
2254+
/// index from the end.
2255+
///
2256+
/// The slice will contain all indices from `[0, len - N)` (excluding
2257+
/// the index `N` itself) and the array will contain all
2258+
/// indices from `[len - N, len)` (excluding the index `len` itself).
2259+
///
2260+
/// # Panics
2261+
///
2262+
/// Panics if `N > len`.
2263+
///
2264+
/// # Examples
2265+
///
2266+
/// ```
2267+
/// #![feature(split_array)]
2268+
///
2269+
/// let mut v = &mut [1, 0, 3, 0, 5, 6][..];
2270+
/// let (left, right) = v.rsplit_array_mut::<4>();
2271+
/// assert_eq!(left, [1, 0]);
2272+
/// assert_eq!(right, &mut [3, 0, 5, 6]);
2273+
/// left[1] = 2;
2274+
/// right[1] = 4;
2275+
/// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
2276+
/// ```
2277+
#[unstable(feature = "split_array", reason = "new API", issue = "90091")]
2278+
#[inline]
2279+
#[must_use]
2280+
pub fn rsplit_array_mut<const N: usize>(&mut self) -> (&mut [T], &mut [T; N]) {
2281+
assert!(N <= self.len());
2282+
let (a, b) = self.split_at_mut(self.len() - N);
2283+
// SAFETY: b points to [T; N]? Yes it's [T] of length N (checked by split_at_mut)
2284+
unsafe { (a, &mut *(b.as_mut_ptr() as *mut [T; N])) }
2285+
}
2286+
20342287
/// Returns an iterator over subslices separated by elements that match
20352288
/// `pred`. The matched element is not contained in the subslices.
20362289
///

0 commit comments

Comments
 (0)