konst/slice/slice_const_methods.rs
1use konst_kernel::{__slice_from_impl, __slice_up_to_impl};
2
3use crate::slice::{BytesPattern, PatternNorm};
4
5/// A const equivalent of `slice.get(index)`
6///
7/// # Example
8///
9/// ```rust
10/// use konst::slice;
11///
12/// const FIBB: &[u16] = &[3, 5, 8];
13///
14/// const ELEM0: Option<&u16> = slice::get(FIBB, 0);
15/// const ELEM1: Option<&u16> = slice::get(FIBB, 1);
16/// const ELEM2: Option<&u16> = slice::get(FIBB, 2);
17/// const ELEM3: Option<&u16> = slice::get(FIBB, 3);
18///
19/// assert_eq!(ELEM0, Some(&3));
20/// assert_eq!(ELEM1, Some(&5));
21/// assert_eq!(ELEM2, Some(&8));
22/// assert_eq!(ELEM3, None);
23///
24/// ```
25#[inline]
26pub const fn get<T>(slice: &[T], index: usize) -> Option<&T> {
27 if slice.len() > index {
28 Some(&slice[index])
29 } else {
30 None
31 }
32}
33
34/// A const equivalent of `slice.get_mut(index)`
35///
36/// # Example
37///
38/// ```rust
39/// use konst::slice;
40///
41/// let mut fibb = [3, 5, 8];
42///
43/// assert_eq!(slice::get_mut(&mut fibb, 0), Some(&mut 3));
44/// assert_eq!(slice::get_mut(&mut fibb, 1), Some(&mut 5));
45/// assert_eq!(slice::get_mut(&mut fibb, 2), Some(&mut 8));
46/// assert_eq!(slice::get_mut(&mut fibb, 3), None);
47///
48/// ```
49#[inline]
50#[cfg(feature = "rust_1_83")]
51#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))]
52pub const fn get_mut<T>(slice: &mut [T], index: usize) -> Option<&mut T> {
53 if slice.len() > index {
54 Some(&mut slice[index])
55 } else {
56 None
57 }
58}
59
60/// A const equivalent of `&slice[start..]`.
61///
62/// If `slice.len() < start`, this simply returns an empty slice.
63///
64/// # Example
65///
66/// ```rust
67/// use konst::slice::slice_from;
68///
69/// const FIBB: &[u16] = &[3, 5, 8, 13, 21, 34, 55, 89];
70///
71/// const TWO: &[u16] = slice_from(FIBB, 2);
72/// const FOUR: &[u16] = slice_from(FIBB, 4);
73/// const ALL: &[u16] = slice_from(FIBB, 0);
74/// const NONE: &[u16] = slice_from(FIBB, 1000);
75///
76/// assert_eq!(TWO, &[8, 13, 21, 34, 55, 89]);
77/// assert_eq!(FOUR, &[21, 34, 55, 89]);
78/// assert_eq!(ALL, FIBB);
79/// assert_eq!(NONE, &[]);
80///
81/// ```
82pub use konst_kernel::slice::slice_from;
83
84/// A const equivalent of `&slice[..len]`.
85///
86/// If `slice.len() < len`, this simply returns `slice` back.
87///
88/// # Example
89///
90/// ```rust
91/// use konst::slice::slice_up_to;
92///
93/// const FIBB: &[u16] = &[3, 5, 8, 13, 21, 34, 55, 89];
94///
95/// const TWO: &[u16] = slice_up_to(FIBB, 2);
96/// const FOUR: &[u16] = slice_up_to(FIBB, 4);
97/// const NONE: &[u16] = slice_up_to(FIBB, 0);
98/// const ALL: &[u16] = slice_up_to(FIBB, 1000);
99///
100/// assert_eq!(TWO, &[3, 5]);
101/// assert_eq!(FOUR, &[3, 5, 8, 13]);
102/// assert_eq!(NONE, &[]);
103/// assert_eq!(ALL, FIBB);
104///
105/// ```
106pub use konst_kernel::slice::slice_up_to;
107
108/// A const equivalent of `&slice[start..end]`.
109///
110/// If `start >= end ` or `slice.len() < start `, this returns an empty slice.
111///
112/// If `slice.len() < end`, this returns the slice from `start`.
113///
114/// # Alternatives
115///
116/// For a const equivalent of `&slice[start..]` there's [`slice_from`].
117///
118/// For a const equivalent of `&slice[..end]` there's [`slice_up_to`].
119///
120/// # Example
121///
122/// ```rust
123/// use konst::slice::slice_range;
124///
125/// const FIBB: &[u16] = &[3, 5, 8, 13, 21, 34, 55, 89];
126///
127/// const TWO: &[u16] = slice_range(FIBB, 2, 4);
128/// const FOUR: &[u16] = slice_range(FIBB, 4, 7);
129/// const NONE: &[u16] = slice_range(FIBB, 0, 0);
130/// const ALL: &[u16] = slice_range(FIBB, 0, 1000);
131///
132/// assert_eq!(TWO, &[8, 13]);
133/// assert_eq!(FOUR, &[21, 34, 55]);
134/// assert_eq!(NONE, &[]);
135/// assert_eq!(ALL, FIBB);
136///
137/// ```
138pub use konst_kernel::slice::slice_range;
139
140/// A const equivalent of `slice.get(start..)`.
141///
142/// # Example
143///
144/// ```rust
145/// use konst::slice;
146///
147/// const FIBB: &[u16] = &[3, 5, 8, 13, 21, 34, 55, 89];
148///
149/// const TWO: Option<&[u16]> = slice::get_from(FIBB, 2);
150/// const FOUR: Option<&[u16]> = slice::get_from(FIBB, 4);
151/// const ALL: Option<&[u16]> = slice::get_from(FIBB, 0);
152/// const NONE: Option<&[u16]> = slice::get_from(FIBB, 1000);
153///
154/// assert_eq!(TWO, Some(&[8, 13, 21, 34, 55, 89][..]));
155/// assert_eq!(FOUR, Some(&[21, 34, 55, 89][..]));
156/// assert_eq!(ALL, Some(FIBB));
157/// assert_eq!(NONE, None);
158///
159/// ```
160#[inline]
161pub const fn get_from<T>(slice: &[T], start: usize) -> Option<&[T]> {
162 Some(__slice_from_impl!(
163 slice,
164 start,
165 as_ptr,
166 from_raw_parts,
167 None
168 ))
169}
170
171/// A const equivalent of `&mut slice[start..]`.
172///
173/// If `slice.len() < start`, this simply returns an empty slice.
174///
175/// # Example
176///
177/// ```rust
178/// use konst::slice::slice_from_mut;
179///
180/// let mut fibs = [3, 5, 8, 13, 21, 34, 55, 89];
181///
182/// assert_eq!(slice_from_mut(&mut fibs, 0), &mut [3, 5, 8, 13, 21, 34, 55, 89]);
183/// assert_eq!(slice_from_mut(&mut fibs, 1), &mut [5, 8, 13, 21, 34, 55, 89]);
184/// assert_eq!(slice_from_mut(&mut fibs, 2), &mut [8, 13, 21, 34, 55, 89]);
185/// assert_eq!(slice_from_mut(&mut fibs, 6), &mut [55, 89]);
186/// assert_eq!(slice_from_mut(&mut fibs, 7), &mut [89]);
187/// assert_eq!(slice_from_mut(&mut fibs, 8), &mut []);
188/// assert_eq!(slice_from_mut(&mut fibs, 1000), &mut []);
189///
190///
191/// ```
192#[inline]
193#[cfg(feature = "rust_1_83")]
194#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))]
195pub const fn slice_from_mut<T>(slice: &mut [T], start: usize) -> &mut [T] {
196 __slice_from_impl!(slice, start, as_mut_ptr, from_raw_parts_mut, &mut [])
197}
198
199/// A const equivalent of `slice.get_mut(start..)`.
200///
201/// # Example
202///
203/// ```rust
204/// use konst::slice;
205///
206/// let mut fibs = [3, 5, 8, 13, 21, 34, 55];
207///
208/// assert_eq!(slice::get_from_mut(&mut fibs, 0), Some(&mut [3, 5, 8, 13, 21, 34, 55][..]));
209/// assert_eq!(slice::get_from_mut(&mut fibs, 1), Some(&mut [5, 8, 13, 21, 34, 55][..]));
210/// assert_eq!(slice::get_from_mut(&mut fibs, 2), Some(&mut [8, 13, 21, 34, 55][..]));
211/// assert_eq!(slice::get_from_mut(&mut fibs, 6), Some(&mut [55][..]));
212/// assert_eq!(slice::get_from_mut(&mut fibs, 7), Some(&mut [][..]));
213/// assert_eq!(slice::get_from_mut(&mut fibs, 8), None);
214/// assert_eq!(slice::get_from_mut(&mut fibs, 100), None);
215///
216///
217/// ```
218#[inline]
219#[cfg(feature = "rust_1_83")]
220#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))]
221pub const fn get_from_mut<T>(slice: &mut [T], start: usize) -> Option<&mut [T]> {
222 Some(__slice_from_impl!(
223 slice,
224 start,
225 as_mut_ptr,
226 from_raw_parts_mut,
227 None
228 ))
229}
230
231/// A const equivalent of `slice.get(..len)`.
232///
233/// # Example
234///
235/// ```rust
236/// use konst::slice;
237///
238/// const FIBB: &[u16] = &[3, 5, 8, 13, 21, 34, 55, 89];
239///
240/// const TWO: Option<&[u16]> = slice::get_up_to(FIBB, 2);
241/// const FOUR: Option<&[u16]> = slice::get_up_to(FIBB, 4);
242/// const NONE: Option<&[u16]> = slice::get_up_to(FIBB, 0);
243/// const ALL: Option<&[u16]> = slice::get_up_to(FIBB, 1000);
244///
245/// assert_eq!(TWO, Some(&[3, 5][..]));
246/// assert_eq!(FOUR, Some(&[3, 5, 8, 13][..]));
247/// assert_eq!(NONE, Some(&[][..]));
248/// assert_eq!(ALL, None);
249///
250/// ```
251#[inline]
252pub const fn get_up_to<T>(slice: &[T], len: usize) -> Option<&[T]> {
253 Some(__slice_up_to_impl!(
254 slice,
255 len,
256 as_ptr,
257 from_raw_parts,
258 None
259 ))
260}
261
262/// A const equivalent of `&mut slice[..len]`.
263///
264/// If `slice.len() < len`, this simply returns `slice` back.
265///
266/// # Example
267///
268/// ```rust
269/// use konst::slice::slice_up_to_mut;
270///
271/// let mut fibs = [3, 5, 8, 13, 21, 34, 55, 89];
272///
273/// assert_eq!(slice_up_to_mut(&mut fibs, 100), &mut [3, 5, 8, 13, 21, 34, 55, 89]);
274/// assert_eq!(slice_up_to_mut(&mut fibs, 8), &mut [3, 5, 8, 13, 21, 34, 55, 89]);
275/// assert_eq!(slice_up_to_mut(&mut fibs, 7), &mut [3, 5, 8, 13, 21, 34, 55]);
276/// assert_eq!(slice_up_to_mut(&mut fibs, 6), &mut [3, 5, 8, 13, 21, 34]);
277/// assert_eq!(slice_up_to_mut(&mut fibs, 3), &mut [3, 5, 8]);
278/// assert_eq!(slice_up_to_mut(&mut fibs, 2), &mut [3, 5]);
279/// assert_eq!(slice_up_to_mut(&mut fibs, 1), &mut [3]);
280/// assert_eq!(slice_up_to_mut(&mut fibs, 0), &mut []);
281///
282///
283/// ```
284#[inline]
285#[cfg(feature = "rust_1_83")]
286#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))]
287pub const fn slice_up_to_mut<T>(slice: &mut [T], len: usize) -> &mut [T] {
288 __slice_up_to_impl!(slice, len, as_mut_ptr, from_raw_parts_mut, slice)
289}
290
291/// A const equivalent of `slice.get_mut(..len)`.
292///
293/// # Example
294///
295/// ```rust
296/// use konst::slice;
297///
298/// let mut fibs = [3, 5, 8, 13, 21, 34, 55, 89];
299///
300/// assert_eq!(slice::get_up_to_mut(&mut fibs, 100), None);
301/// assert_eq!(slice::get_up_to_mut(&mut fibs, 9), None);
302/// assert_eq!(slice::get_up_to_mut(&mut fibs, 8), Some(&mut [3, 5, 8, 13, 21, 34, 55, 89][..]));
303/// assert_eq!(slice::get_up_to_mut(&mut fibs, 7), Some(&mut [3, 5, 8, 13, 21, 34, 55][..]));
304/// assert_eq!(slice::get_up_to_mut(&mut fibs, 6), Some(&mut [3, 5, 8, 13, 21, 34][..]));
305/// assert_eq!(slice::get_up_to_mut(&mut fibs, 3), Some(&mut [3, 5, 8][..]));
306/// assert_eq!(slice::get_up_to_mut(&mut fibs, 2), Some(&mut [3, 5][..]));
307/// assert_eq!(slice::get_up_to_mut(&mut fibs, 1), Some(&mut [3][..]));
308/// assert_eq!(slice::get_up_to_mut(&mut fibs, 0), Some(&mut [][..]));
309///
310/// ```
311#[inline]
312#[cfg(feature = "rust_1_83")]
313#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))]
314pub const fn get_up_to_mut<T>(slice: &mut [T], len: usize) -> Option<&mut [T]> {
315 Some(__slice_up_to_impl!(
316 slice,
317 len,
318 as_mut_ptr,
319 from_raw_parts_mut,
320 None
321 ))
322}
323
324/// A const equivalent of `slice.get(start..end)`.
325///
326/// # Alternatives
327///
328/// For a const equivalent of `slice.get(start..)` there's [`get_from`].
329///
330/// For a const equivalent of `slice.get(..end)` there's [`get_up_to`].
331///
332/// [`get_from`]: ./fn.get_from.html
333/// [`get_up_to`]: ./fn.get_up_to.html
334///
335/// # Example
336///
337/// ```rust
338/// use konst::slice;
339///
340/// const FIBB: &[u16] = &[3, 5, 8, 13, 21, 34, 55, 89];
341///
342/// const TWO: Option<&[u16]> = slice::get_range(FIBB, 2, 4);
343/// const FOUR: Option<&[u16]> = slice::get_range(FIBB, 4, 7);
344/// const ALL: Option<&[u16]> = slice::get_range(FIBB, 0, 8);
345/// const EMPTY: Option<&[u16]> = slice::get_range(FIBB, 0, 0);
346/// const NONE: Option<&[u16]> = slice::get_range(FIBB, 0, 1000);
347///
348/// assert_eq!(TWO, Some(&[8, 13][..]));
349/// assert_eq!(FOUR, Some(&[21, 34, 55][..]));
350/// assert_eq!(ALL, Some(FIBB));
351/// assert_eq!(EMPTY, Some(&[][..]));
352/// assert_eq!(NONE, None);
353///
354/// ```
355pub const fn get_range<T>(slice: &[T], start: usize, end: usize) -> Option<&[T]> {
356 let x = crate::try_opt!(get_up_to(slice, end));
357 get_from(x, start)
358}
359
360/// A const equivalent of `&mut slice[start..end]`.
361///
362/// If `start >= end ` or `slice.len() < start `, this returns an empty slice.
363///
364/// If `slice.len() < end`, this returns the slice from `start`.
365///
366///
367/// # Alternatives
368///
369/// For a const equivalent of `&mut slice[start..]` there's [`slice_from_mut`].
370///
371/// For a const equivalent of `&mut slice[..end]` there's [`slice_up_to_mut`].
372///
373/// [`slice_from_mut`]: ./fn.slice_from_mut.html
374/// [`slice_up_to_mut`]: ./fn.slice_up_to_mut.html
375///
376/// # Example
377///
378/// ```rust
379/// use konst::slice::slice_range_mut;
380///
381/// let mut fibb = [3, 5, 8, 13, 21, 34, 55, 89];
382///
383/// assert_eq!(slice_range_mut(&mut fibb, 2, 4), &mut [8, 13]);
384/// assert_eq!(slice_range_mut(&mut fibb, 4, 7), &mut [21, 34, 55]);
385/// assert_eq!(slice_range_mut(&mut fibb, 0, 0), &mut []);
386/// assert_eq!(slice_range_mut(&mut fibb, 0, 1000), &mut [3, 5, 8, 13, 21, 34, 55, 89]);
387///
388/// ```
389#[inline]
390#[cfg(feature = "rust_1_83")]
391#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))]
392pub const fn slice_range_mut<T>(slice: &mut [T], start: usize, end: usize) -> &mut [T] {
393 slice_from_mut(slice_up_to_mut(slice, end), start)
394}
395
396/// A const equivalent of `slice.get_mut(start..end)`.
397///
398///
399/// # Alternatives
400///
401/// For a const equivalent of `slice.get_mut(start..)` there's [`get_from_mut`].
402///
403/// For a const equivalent of `slice.get_mut(..end)` there's [`get_up_to_mut`].
404///
405/// [`get_from_mut`]: ./fn.get_from_mut.html
406/// [`get_up_to_mut`]: ./fn.get_up_to_mut.html
407///
408/// # Example
409///
410/// ```rust
411/// use konst::slice;
412///
413/// let mut fibb = [3, 5, 8, 13, 21, 34, 55];
414///
415/// assert_eq!(slice::get_range_mut(&mut fibb, 0, 0), Some(&mut [][..]));
416/// assert_eq!(slice::get_range_mut(&mut fibb, 2, 4), Some(&mut [8, 13][..]));
417/// assert_eq!(slice::get_range_mut(&mut fibb, 4, 7), Some(&mut [21, 34, 55][..]));
418/// assert_eq!(slice::get_range_mut(&mut fibb, 0, 7), Some(&mut [3, 5, 8, 13, 21, 34, 55][..]));
419/// assert_eq!(slice::get_range_mut(&mut fibb, 0, 1000), None);
420///
421/// ```
422#[inline]
423#[cfg(feature = "rust_1_83")]
424#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))]
425pub const fn get_range_mut<T>(slice: &mut [T], start: usize, end: usize) -> Option<&mut [T]> {
426 let x = crate::try_opt!(get_up_to_mut(slice, end));
427 get_from_mut(x, start)
428}
429
430/// A const equivalent of
431/// [`<[T]>::split_at`](https://doc.rust-lang.org/std/primitive.slice.html#method.split_at)
432///
433/// If `at > slice.len()`, this returns a `slice`, empty slice pair.
434///
435/// # Const stabilization
436///
437/// The analogous std function was const-stabilized in Rust 1.71.0.
438///
439/// # Example
440///
441/// ```rust
442/// use konst::slice::split_at;
443///
444/// let arr = [3, 5, 8, 13, 21, 34];
445///
446/// assert_eq!(split_at(&arr, 0), (&[][..], &[3, 5, 8, 13, 21, 34][..]));
447///
448/// assert_eq!(split_at(&arr, 1), (&[3][..], &[5, 8, 13, 21, 34][..]));
449///
450/// assert_eq!(split_at(&arr, 2), (&[3, 5][..], &[8, 13, 21, 34][..]));
451///
452/// assert_eq!(split_at(&arr, 5), (&[3, 5, 8, 13, 21][..], &[34][..]));
453///
454/// assert_eq!(split_at(&arr, 6), (&[3, 5, 8, 13, 21, 34][..], &[][..]));
455///
456/// assert_eq!(split_at(&arr, 7), (&[3, 5, 8, 13, 21, 34][..], &[][..]));
457///
458/// ```
459///
460pub const fn split_at<T>(slice: &[T], at: usize) -> (&[T], &[T]) {
461 (slice_up_to(slice, at), slice_from(slice, at))
462}
463
464/// A const equivalent of
465/// [`<[T]>::split_at_mut`
466/// ](https://doc.rust-lang.org/std/primitive.slice.html#method.split_at_mut)
467///
468/// If `at > slice.len()`, this returns a `slice`, empty slice pair.
469///
470/// # Const stabilization
471///
472/// The analogous std function was const-stabilized in Rust 1.83.0.
473///
474/// # Example
475///
476/// ```rust
477/// use konst::slice::split_at_mut;
478///
479/// let mut arr = [3, 5, 8, 13, 21, 34];
480///
481/// assert_eq!(split_at_mut(&mut arr, 0), (&mut [][..], &mut [3, 5, 8, 13, 21, 34][..]));
482///
483/// assert_eq!(split_at_mut(&mut arr, 1), (&mut [3][..], &mut [5, 8, 13, 21, 34][..]));
484///
485/// assert_eq!(split_at_mut(&mut arr, 2), (&mut [3, 5][..], &mut [8, 13, 21, 34][..]));
486///
487/// assert_eq!(split_at_mut(&mut arr, 5), (&mut [3, 5, 8, 13, 21][..], &mut [34][..]));
488///
489/// assert_eq!(split_at_mut(&mut arr, 6), (&mut [3, 5, 8, 13, 21, 34][..], &mut [][..]));
490///
491/// assert_eq!(split_at_mut(&mut arr, 7), (&mut [3, 5, 8, 13, 21, 34][..], &mut [][..]));
492///
493/// ```
494///
495#[inline]
496#[cfg(feature = "rust_1_83")]
497#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))]
498pub const fn split_at_mut<T>(slice: &mut [T], at: usize) -> (&mut [T], &mut [T]) {
499 use core::slice::from_raw_parts_mut;
500
501 if at > slice.len() {
502 return (slice, &mut []);
503 }
504
505 let suffix_len = slice.len() - at;
506
507 unsafe {
508 let ptr = slice.as_mut_ptr();
509
510 let prefix = from_raw_parts_mut(ptr.offset(0), at);
511 let suffix = from_raw_parts_mut(ptr.offset(at as isize), suffix_len);
512
513 (prefix, suffix)
514 }
515}
516
517/// Whether `pattern` is the start of `left`.
518///
519/// This is analogous to
520/// [`<[u8]>::starts_with`](https://doc.rust-lang.org/std/primitive.slice.html#method.starts_with)
521///
522/// # Example
523///
524/// ```rust
525/// use konst::slice::bytes_start_with;
526///
527/// assert!( bytes_start_with(b"foo,bar,baz", "foo,"));
528/// assert!( bytes_start_with(b"foo,bar,baz", &'f'));
529/// assert!( bytes_start_with(b"foo,bar,baz", &[b'f', b'o', b'o']));
530/// assert!(!bytes_start_with(b"foo,bar,baz", "bar"));
531/// assert!(!bytes_start_with(b"foo,bar,baz", "baz"));
532///
533/// ```
534///
535#[inline]
536pub const fn bytes_start_with<const N: usize, P>(left: &[u8], pattern: &P) -> bool
537where
538 P: ?Sized + BytesPattern<N>,
539{
540 let pattern = PatternNorm::new(pattern);
541 __bytes_start_with(left, pattern.as_bytes())
542}
543#[inline(always)]
544pub(crate) const fn __bytes_start_with(left: &[u8], pattern: &[u8]) -> bool {
545 matches!(__bytes_strip_prefix(left, pattern), Some(_))
546}
547
548/// Remove `prefix` from the start of `left`.
549///
550/// Returns `None` if `prefix` is not the start of `left`.
551///
552/// This is analogous to
553/// [`<[u8]>::strip_prefix`](https://doc.rust-lang.org/std/primitive.slice.html#method.strip_prefix)
554///
555/// # Example
556///
557/// ```rust
558/// use konst::slice::bytes_strip_prefix;
559///
560/// assert_eq!(bytes_strip_prefix(b"foo,bar,baz", b"foo,"), Some("bar,baz".as_bytes()));
561/// assert_eq!(bytes_strip_prefix(b"foo,bar,baz", "foo,bar,"), Some("baz".as_bytes()));
562/// assert_eq!(bytes_strip_prefix(b"foo,bar,baz", &'f'), Some("oo,bar,baz".as_bytes()));
563///
564/// assert_eq!(bytes_strip_prefix(b"foo,bar,baz", b"bar"), None);
565/// assert_eq!(bytes_strip_prefix(b"foo,bar,baz", b"baz"), None);
566///
567/// ```
568///
569/// [`strip_prefix`]:
570/// https://doc.rust-lang.org/std/primitive.slice.html#method.strip_prefix
571///
572#[inline]
573pub const fn bytes_strip_prefix<'a, const N: usize, P>(
574 left: &'a [u8],
575 prefix: &P,
576) -> Option<&'a [u8]>
577where
578 P: ?Sized + BytesPattern<N>,
579{
580 let prefix = PatternNorm::new(prefix);
581 __bytes_strip_prefix(left, prefix.as_bytes())
582}
583pub(crate) const fn __bytes_strip_prefix<'a>(
584 mut left: &'a [u8],
585 mut prefix: &[u8],
586) -> Option<&'a [u8]> {
587 impl_bytes_function! {
588 strip_prefix;
589 left = left;
590 right = prefix;
591 on_error = return None,
592 }
593 Some(left)
594}
595
596/// Whether `pattern` is the end of `left`.
597///
598/// A const analog of
599/// [`<[u8]>::ends_with`](https://doc.rust-lang.org/std/primitive.slice.html#method.ends_with)
600///
601/// # Example
602///
603/// ```rust
604/// use konst::slice::bytes_end_with;
605///
606/// assert!( bytes_end_with(b"foo,bar,baz", b",baz"));
607/// assert!( bytes_end_with(b"foo,bar,baz", "bar,baz"));
608/// assert!( bytes_end_with(b"foo,bar,baz", &'z'));
609///
610/// assert!(!bytes_end_with(b"foo,bar,baz", b"bar"));
611/// assert!(!bytes_end_with(b"foo,bar,baz", b"foo"));
612///
613/// ```
614///
615#[inline]
616pub const fn bytes_end_with<const N: usize, P>(left: &[u8], pattern: &P) -> bool
617where
618 P: ?Sized + BytesPattern<N>,
619{
620 let pattern = PatternNorm::new(pattern);
621 __bytes_end_with(left, pattern.as_bytes())
622}
623pub(crate) const fn __bytes_end_with(left: &[u8], pattern: &[u8]) -> bool {
624 matches!(__bytes_strip_suffix(left, pattern), Some(_))
625}
626
627/// Remove `suffix` from the end of `left`.
628///
629/// Returns `None` if `suffix` is not the end of `left`.
630///
631/// A const analog of
632/// [`<[u8]>::strip_suffix`](https://doc.rust-lang.org/std/primitive.slice.html#method.strip_suffix)
633///
634/// # Example
635///
636/// ```rust
637/// use konst::slice::bytes_strip_suffix;
638///
639/// assert_eq!(bytes_strip_suffix(b"foo,bar,baz", b",baz"), Some("foo,bar".as_bytes()));
640/// assert_eq!(bytes_strip_suffix(b"foo,bar,baz", ",bar,baz"), Some("foo".as_bytes()));
641/// assert_eq!(bytes_strip_suffix(b"foo,bar,baz", &'z'), Some("foo,bar,ba".as_bytes()));
642///
643/// assert_eq!(bytes_strip_suffix(b"foo,bar,baz", b"bar"), None);
644/// assert_eq!(bytes_strip_suffix(b"foo,bar,baz", "foo"), None);
645///
646/// ```
647///
648/// [`strip_suffix`]:
649/// https://doc.rust-lang.org/std/primitive.slice.html#method.strip_suffix
650///
651#[inline]
652pub const fn bytes_strip_suffix<'a, const N: usize, P>(
653 left: &'a [u8],
654 suffix: &P,
655) -> Option<&'a [u8]>
656where
657 P: ?Sized + BytesPattern<N>,
658{
659 let suffix = PatternNorm::new(suffix);
660 __bytes_strip_suffix(left, suffix.as_bytes())
661}
662pub(crate) const fn __bytes_strip_suffix<'a>(
663 mut left: &'a [u8],
664 mut suffix: &[u8],
665) -> Option<&'a [u8]> {
666 impl_bytes_function! {
667 strip_suffix;
668 left = left;
669 right = suffix;
670 on_error = return None,
671 }
672 Some(left)
673}
674
675/// Finds the byte offset of `pattern` in `left`.
676///
677/// Returns `None` if `pattern` isn't inside `left`
678///
679/// # Example
680///
681/// ```rust
682/// use konst::slice::bytes_find;
683///
684/// assert_eq!(bytes_find(b"foo-bar-baz", &'q'), None);
685/// assert_eq!(bytes_find(b"foo-bar-baz", "foo"), Some(0));
686/// assert_eq!(bytes_find(b"foo-bar-baz", b"bar"), Some(4));
687/// assert_eq!(bytes_find(b"foo-bar-baz", b"baz"), Some(8));
688///
689/// ```
690///
691#[inline]
692pub const fn bytes_find<const N: usize, P>(left: &[u8], pattern: &P) -> Option<usize>
693where
694 P: ?Sized + BytesPattern<N>,
695{
696 let pattern = PatternNorm::new(pattern);
697 __bytes_find(left, pattern.as_bytes())
698}
699pub(crate) const fn __bytes_find(left: &[u8], pattern: &[u8]) -> Option<usize> {
700 let mut matching = pattern;
701
702 crate::for_range! {i in 0..left.len() =>
703 match matching {
704 [mb, m_rem @ ..] => {
705 let b = left[i];
706
707 matching = if b == *mb {
708 m_rem
709 } else {
710 match pattern {
711 // For when the string is "lawlawn" and we are trying to find "lawn"
712 [mb2, m_rem2 @ ..] if b == *mb2 => m_rem2,
713 _ => pattern,
714 }
715 };
716 }
717 [] => {
718 return Some(i - pattern.len())
719 }
720 }
721 }
722
723 if matching.is_empty() {
724 Some(left.len() - pattern.len())
725 } else {
726 None
727 }
728}
729
730/// Whether `pattern` is inside `left`.
731///
732/// # Example
733///
734/// ```rust
735/// use konst::slice::bytes_contain;
736///
737/// assert!(bytes_contain(b"foo-bar", b"foo"));
738/// assert!(bytes_contain(b"bar-foo", "foo"));
739///
740/// assert!(!bytes_contain(b"foo-bar-baz", &'q'));
741///
742/// ```
743///
744#[inline]
745pub const fn bytes_contain<const N: usize, P>(left: &[u8], pattern: &P) -> bool
746where
747 P: ?Sized + BytesPattern<N>,
748{
749 let pattern = PatternNorm::new(pattern);
750 __bytes_contain(left, pattern.as_bytes())
751}
752#[inline(always)]
753const fn __bytes_contain(left: &[u8], pattern: &[u8]) -> bool {
754 matches!(__bytes_find(left, pattern), Some(_))
755}
756
757/// Finds the byte offset of `pattern` inside `left`, searching in reverse.
758///
759/// Returns `None` if `pattern` isn't inside `left`.
760///
761/// # Example
762///
763/// ```rust
764/// use konst::slice::bytes_rfind;
765///
766/// assert_eq!(bytes_rfind(b"foo-bar-baz", &'q'), None);
767/// assert_eq!(bytes_rfind(b"foo-bar-baz", b"foo"), Some(0));
768/// assert_eq!(bytes_rfind(b"foo-bar-baz", "bar"), Some(4));
769/// assert_eq!(bytes_rfind(b"foo-bar-baz", b"baz"), Some(8));
770///
771/// ```
772///
773#[inline]
774pub const fn bytes_rfind<const N: usize, P>(left: &[u8], pattern: &P) -> Option<usize>
775where
776 P: ?Sized + BytesPattern<N>,
777{
778 let pattern = PatternNorm::new(pattern);
779 __bytes_rfind(left, pattern.as_bytes())
780}
781pub(crate) const fn __bytes_rfind(left: &[u8], pattern: &[u8]) -> Option<usize> {
782 let mut matching = pattern;
783
784 let llen = left.len();
785
786 let mut i = llen;
787
788 while i != 0 {
789 i -= 1;
790
791 match matching {
792 [m_rem @ .., mb] => {
793 let b = left[i];
794
795 matching = if b == *mb {
796 m_rem
797 } else {
798 match pattern {
799 // For when the string is "lawlawn" and we are trying to find "lawn"
800 [m_rem2 @ .., mb2] if b == *mb2 => m_rem2,
801 _ => pattern,
802 }
803 };
804 }
805 [] => return Some(i + (!pattern.is_empty()) as usize),
806 }
807 }
808
809 if matching.is_empty() {
810 Some(i)
811 } else {
812 None
813 }
814}
815
816/// Returns whether `pattern` is contained inside `left`, searching in reverse.
817///
818/// # Example
819///
820/// ```rust
821/// use konst::slice::bytes_rcontain;
822///
823/// assert!(bytes_rcontain(b"foo-bar", b"foo"));
824/// assert!(bytes_rcontain(b"bar-foo", "foo"));
825///
826/// assert!(!bytes_rcontain(b"foo-bar-baz", &'q'));
827///
828/// ```
829///
830#[inline]
831pub const fn bytes_rcontain<const N: usize, P>(left: &[u8], pattern: &P) -> bool
832where
833 P: ?Sized + BytesPattern<N>,
834{
835 let pattern = PatternNorm::new(pattern);
836 __bytes_rcontain(left, pattern.as_bytes())
837}
838#[inline(always)]
839pub(crate) const fn __bytes_rcontain(left: &[u8], pattern: &[u8]) -> bool {
840 matches!(bytes_rfind(left, pattern), Some(_))
841}
842
843macro_rules! matches_space {
844 ($b:ident) => {
845 matches!($b, b'\t' | b'\n' | b'\r' | b' ')
846 };
847}
848
849/// Removes ascii whitespace from the start and end of `this`.
850///
851/// # Const stabilization
852///
853/// The [equivalent std function](
854/// https://doc.rust-lang.org/std/primitive.slice.html#method.trim_ascii)
855/// was const-stabilized in Rust 1.80.0.
856///
857/// # Example
858///
859/// ```rust
860/// use konst::slice;
861///
862/// const TRIMMED: &[u8] = slice::bytes_trim(b"\nhello world ");
863///
864/// assert_eq!(TRIMMED, b"hello world");
865///
866/// ```
867pub const fn bytes_trim(this: &[u8]) -> &[u8] {
868 bytes_trim_start(bytes_trim_end(this))
869}
870
871/// Removes ascii whitespace from the start of `this`.
872///
873/// # Const stabilization
874///
875/// The [equivalent std function](
876/// https://doc.rust-lang.org/std/primitive.slice.html#method.trim_ascii_start)
877/// was const-stabilized in Rust 1.80.0.
878///
879/// # Example
880///
881/// ```rust
882/// use konst::slice;
883///
884/// const TRIMMED: &[u8] = slice::bytes_trim_start(b"\tfoo bar ");
885///
886/// assert_eq!(TRIMMED, b"foo bar ");
887///
888/// ```
889pub const fn bytes_trim_start(mut this: &[u8]) -> &[u8] {
890 loop {
891 match this {
892 [b, rem @ ..] if matches_space!(b) => this = rem,
893 _ => return this,
894 }
895 }
896}
897
898/// Removes ascii whitespace from the end of `this`.
899///
900/// # Const stabilization
901///
902/// The [equivalent std function](
903/// https://doc.rust-lang.org/std/primitive.slice.html#method.trim_ascii_end)
904/// was const-stabilized in Rust 1.80.0.
905///
906/// # Example
907///
908/// ```rust
909/// use konst::slice;
910///
911/// const TRIMMED: &[u8] = slice::bytes_trim_end(b"\rfoo bar ");
912///
913/// assert_eq!(TRIMMED, b"\rfoo bar");
914///
915/// ```
916pub const fn bytes_trim_end(mut this: &[u8]) -> &[u8] {
917 loop {
918 match this {
919 [rem @ .., b] if matches_space!(b) => this = rem,
920 _ => return this,
921 }
922 }
923}
924
925/// Removes all instances of `needle` from the start and end of `this`.
926///
927/// # Example
928///
929/// ```rust
930/// use konst::slice;
931///
932/// const TRIMMED0: &[u8] = slice::bytes_trim_matches(b"<>baz qux<><><>", b"<>");
933/// assert_eq!(TRIMMED0, b"baz qux");
934///
935/// const TRIMMED1: &[u8] = slice::bytes_trim_matches(b"{}foo bar{}{}", "{}");
936/// assert_eq!(TRIMMED1, b"foo bar");
937///
938/// const TRIMMED2: &[u8] = slice::bytes_trim_matches(b"-----soming----", &'-');
939/// assert_eq!(TRIMMED2, b"soming");
940///
941///
942/// ```
943pub const fn bytes_trim_matches<'a, const N: usize, P>(this: &'a [u8], needle: &P) -> &'a [u8]
944where
945 P: ?Sized + BytesPattern<N>,
946{
947 let needle = PatternNorm::new(needle);
948 __bytes_trim_matches(this, needle.as_bytes())
949}
950pub(crate) const fn __bytes_trim_matches<'a>(this: &'a [u8], needle: &[u8]) -> &'a [u8] {
951 let ltrim = __bytes_trim_start_matches(this, needle);
952 __bytes_trim_end_matches(ltrim, needle)
953}
954
955/// Removes all instances of `needle` from the start of `this`.
956///
957/// # Example
958///
959/// ```rust
960/// use konst::slice;
961///
962/// const TRIMMED0: &[u8] = slice::bytes_trim_start_matches(b"#####huh###", b"##");
963/// const TRIMMED1: &[u8] = slice::bytes_trim_start_matches(b"[][]nice[][]", "[][]");
964/// const TRIMMED2: &[u8] = slice::bytes_trim_start_matches(b"(((woah", &'(');
965///
966/// assert_eq!(TRIMMED0, b"#huh###");
967/// assert_eq!(TRIMMED1, b"nice[][]");
968/// assert_eq!(TRIMMED2, b"woah");
969///
970/// ```
971pub const fn bytes_trim_start_matches<'a, const N: usize, P>(this: &'a [u8], needle: &P) -> &'a [u8]
972where
973 P: ?Sized + BytesPattern<N>,
974{
975 let needle = PatternNorm::new(needle);
976 __bytes_trim_start_matches(this, needle.as_bytes())
977}
978pub(crate) const fn __bytes_trim_start_matches<'a>(mut this: &'a [u8], needle: &[u8]) -> &'a [u8] {
979 if needle.is_empty() {
980 return this;
981 }
982
983 let mut matched = needle;
984
985 loop {
986 let at_start = this;
987
988 match (this, matched) {
989 ([b, rem @ ..], [bm, remm @ ..]) if *b == *bm => {
990 this = rem;
991 matched = remm;
992 }
993 _ => return this,
994 }
995
996 'inner: loop {
997 match (this, matched) {
998 ([], [_, ..]) => return at_start,
999 ([b, rem @ ..], [bm, remm @ ..]) => {
1000 if *b == *bm {
1001 this = rem;
1002 matched = remm;
1003 } else {
1004 return at_start;
1005 }
1006 }
1007 _ => break 'inner,
1008 }
1009 }
1010
1011 matched = needle;
1012 }
1013}
1014
1015/// Removes all instances of `needle` from the end of `this`.
1016///
1017/// # Example
1018///
1019/// ```rust
1020/// use konst::slice;
1021///
1022/// const TRIMMED0: &[u8] = slice::bytes_trim_end_matches(b"oowowooooo", b"oo");
1023/// const TRIMMED1: &[u8] = slice::bytes_trim_end_matches(b"gooooo", "oo");
1024/// const TRIMMED2: &[u8] = slice::bytes_trim_end_matches(b"yesssssss", &'s');
1025///
1026/// assert_eq!(TRIMMED0, b"oowowo");
1027/// assert_eq!(TRIMMED1, b"go");
1028/// assert_eq!(TRIMMED2, b"ye");
1029///
1030/// ```
1031pub const fn bytes_trim_end_matches<'a, const N: usize, P>(this: &'a [u8], needle: &P) -> &'a [u8]
1032where
1033 P: ?Sized + BytesPattern<N>,
1034{
1035 let needle = PatternNorm::new(needle);
1036 __bytes_trim_end_matches(this, needle.as_bytes())
1037}
1038pub(crate) const fn __bytes_trim_end_matches<'a>(mut this: &'a [u8], needle: &[u8]) -> &'a [u8] {
1039 if needle.is_empty() {
1040 return this;
1041 }
1042
1043 let mut matched = needle;
1044
1045 loop {
1046 let at_start = this;
1047
1048 match (this, matched) {
1049 ([rem @ .., b], [remm @ .., bm]) if *b == *bm => {
1050 this = rem;
1051 matched = remm;
1052 }
1053 _ => return this,
1054 }
1055
1056 'inner: loop {
1057 match (this, matched) {
1058 ([], [.., _]) => return at_start,
1059 ([rem @ .., b], [remm @ .., bm]) => {
1060 if *b == *bm {
1061 this = rem;
1062 matched = remm;
1063 } else {
1064 return at_start;
1065 }
1066 }
1067 _ => break 'inner,
1068 }
1069 }
1070
1071 matched = needle;
1072 }
1073}
1074
1075macro_rules! elem_then_rem {
1076 ($elem:ident, $($rem:tt)*) => { [$elem, $($rem)*] };
1077}
1078
1079macro_rules! rem_then_elem {
1080 ($elem:ident, $($rem:tt)*) => { [$($rem)*, $elem] };
1081}
1082
1083macro_rules! byte_find_then {
1084 ($slice_order:ident, $this:ident, $needle:ident, |$next:ident| $then:block) => ({
1085 if $needle.is_empty() {
1086 return Some($this);
1087 }
1088
1089 let mut matching = $needle;
1090
1091 let mut $next = $this;
1092
1093 while let $slice_order!(mb, ref m_rem @ ..) = *matching {
1094 matching = m_rem;
1095
1096 if let $slice_order!(b, ref rem @ ..) = *$next {
1097 if b != mb {
1098 matching = match *$needle {
1099 // For when the string is "lawlawn" and we are skipping "lawn"
1100 $slice_order!(mb2, ref m_rem2 @ ..) if b == mb2 => {
1101 // This is considered used in half of the macro invocations
1102 #[allow(unused_assignments)]
1103 {$this = $next;}
1104 m_rem2
1105 },
1106 _ => {
1107 // This is considered used in half of the macro invocations
1108 #[allow(unused_assignments)]
1109 {$this = rem;}
1110 $needle
1111 },
1112 };
1113 }
1114 $next = rem;
1115 } else {
1116 return None;
1117 }
1118 }
1119
1120 $then
1121
1122 Some($this)
1123 });
1124}
1125
1126/// Advances `this` past the first instance of `needle`.
1127///
1128/// Return `None` if no instance of `needle` is found.
1129///
1130/// Return `Some(this)` if `needle` is empty.
1131///
1132/// # Example
1133///
1134/// ```rust
1135/// use konst::slice::bytes_find_skip;
1136///
1137/// {
1138/// const FOUND: Option<&[u8]> = bytes_find_skip(b"foo bar baz", b"bar");
1139/// assert_eq!(FOUND, Some(&b" baz"[..]));
1140/// }
1141/// {
1142/// const NOT_FOUND: Option<&[u8]> = bytes_find_skip(b"foo bar baz", &'q');
1143/// assert_eq!(NOT_FOUND, None);
1144/// }
1145/// {
1146/// const EMPTY_NEEDLE: Option<&[u8]> = bytes_find_skip(b"foo bar baz", "");
1147/// assert_eq!(EMPTY_NEEDLE, Some(&b"foo bar baz"[..]));
1148/// }
1149/// ```
1150pub const fn bytes_find_skip<'a, const N: usize, P>(this: &'a [u8], needle: &P) -> Option<&'a [u8]>
1151where
1152 P: ?Sized + BytesPattern<N>,
1153{
1154 let needle = PatternNorm::new(needle);
1155 __bytes_find_skip(this, needle.as_bytes())
1156}
1157pub(crate) const fn __bytes_find_skip<'a>(mut this: &'a [u8], needle: &[u8]) -> Option<&'a [u8]> {
1158 byte_find_then! {elem_then_rem, this, needle, |next| {this = next}}
1159}
1160
1161/// Advances `this` up to the first instance of `needle`.
1162///
1163/// Return `None` if no instance of `needle` is found.
1164///
1165/// Return `Some(this)` if `needle` is empty.
1166///
1167/// # Example
1168///
1169/// ```rust
1170/// use konst::slice::bytes_find_keep;
1171///
1172/// {
1173/// const FOUND: Option<&[u8]> = bytes_find_keep(b"foo bar baz", b"bar");
1174/// assert_eq!(FOUND, Some(&b"bar baz"[..]));
1175/// }
1176/// {
1177/// const NOT_FOUND: Option<&[u8]> = bytes_find_keep(b"foo bar baz", &'q');
1178/// assert_eq!(NOT_FOUND, None);
1179/// }
1180/// {
1181/// const EMPTY_NEEDLE: Option<&[u8]> = bytes_find_keep(b"foo bar baz", "");
1182/// assert_eq!(EMPTY_NEEDLE, Some(&b"foo bar baz"[..]));
1183/// }
1184/// ```
1185pub const fn bytes_find_keep<'a, const N: usize, P>(this: &'a [u8], needle: &P) -> Option<&'a [u8]>
1186where
1187 P: ?Sized + BytesPattern<N>,
1188{
1189 let needle = PatternNorm::new(needle);
1190 __bytes_find_keep(this, needle.as_bytes())
1191}
1192pub(crate) const fn __bytes_find_keep<'a>(mut this: &'a [u8], needle: &[u8]) -> Option<&'a [u8]> {
1193 byte_find_then! {elem_then_rem, this, needle, |next| {}}
1194}
1195
1196/// Truncates `this` to before the last instance of `needle`.
1197///
1198/// Return `None` if no instance of `needle` is found.
1199///
1200/// Return `Some(this)` if `needle` is empty.
1201///
1202/// # Example
1203///
1204/// ```rust
1205/// use konst::slice::bytes_rfind_skip;
1206///
1207/// {
1208/// const FOUND: Option<&[u8]> = bytes_rfind_skip(b"foo bar _ bar baz", b"bar");
1209/// assert_eq!(FOUND, Some(&b"foo bar _ "[..]));
1210/// }
1211/// {
1212/// const NOT_FOUND: Option<&[u8]> = bytes_rfind_skip(b"foo bar baz", &'q');
1213/// assert_eq!(NOT_FOUND, None);
1214/// }
1215/// {
1216/// const EMPTY_NEEDLE: Option<&[u8]> = bytes_rfind_skip(b"foo bar baz", "");
1217/// assert_eq!(EMPTY_NEEDLE, Some(&b"foo bar baz"[..]));
1218/// }
1219/// ```
1220pub const fn bytes_rfind_skip<'a, const N: usize, P>(this: &'a [u8], needle: &P) -> Option<&'a [u8]>
1221where
1222 P: ?Sized + BytesPattern<N>,
1223{
1224 let needle = PatternNorm::new(needle);
1225 __bytes_rfind_skip(this, needle.as_bytes())
1226}
1227pub(crate) const fn __bytes_rfind_skip<'a>(mut this: &'a [u8], needle: &[u8]) -> Option<&'a [u8]> {
1228 byte_find_then! {rem_then_elem, this, needle, |next| {this = next}}
1229}
1230
1231/// Truncates `this` to the last instance of `needle`.
1232///
1233/// Return `None` if no instance of `needle` is found.
1234///
1235/// Return `Some(this)` if `needle` is empty.
1236///
1237/// # Example
1238///
1239/// ```rust
1240/// use konst::slice::bytes_rfind_keep;
1241///
1242/// {
1243/// const FOUND: Option<&[u8]> = bytes_rfind_keep(b"foo bar _ bar baz", b"bar");
1244/// assert_eq!(FOUND, Some(&b"foo bar _ bar"[..]));
1245/// }
1246/// {
1247/// const NOT_FOUND: Option<&[u8]> = bytes_rfind_keep(b"foo bar baz", &'q');
1248/// assert_eq!(NOT_FOUND, None);
1249/// }
1250/// {
1251/// const EMPTY_NEEDLE: Option<&[u8]> = bytes_rfind_keep(b"foo bar baz", "");
1252/// assert_eq!(EMPTY_NEEDLE, Some(&b"foo bar baz"[..]));
1253/// }
1254/// ```
1255pub const fn bytes_rfind_keep<'a, const N: usize, P>(this: &'a [u8], needle: &P) -> Option<&'a [u8]>
1256where
1257 P: ?Sized + BytesPattern<N>,
1258{
1259 let needle = PatternNorm::new(needle);
1260 __bytes_rfind_keep(this, needle.as_bytes())
1261}
1262pub(crate) const fn __bytes_rfind_keep<'a>(mut this: &'a [u8], needle: &[u8]) -> Option<&'a [u8]> {
1263 byte_find_then! {rem_then_elem, this, needle, |next| {}}
1264}
1265
1266/// A const equivalent of
1267/// [`<[T]>::first_mut`](https://doc.rust-lang.org/std/primitive.slice.html#method.first_mut)
1268///
1269/// # Example
1270///
1271/// ```rust
1272/// use konst::slice;
1273///
1274/// assert_eq!(slice::first_mut(&mut [8, 5, 3]), Some(&mut 8));
1275///
1276/// assert_eq!(slice::first_mut(&mut [5, 3]), Some(&mut 5));
1277///
1278/// assert_eq!(slice::first_mut(&mut [3]), Some(&mut 3));
1279///
1280/// assert_eq!(slice::first_mut::<u8>(&mut []), None);
1281///
1282/// ```
1283///
1284#[cfg(feature = "rust_1_83")]
1285#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))]
1286pub const fn first_mut<T>(slice: &mut [T]) -> Option<&mut T> {
1287 if let [first, ..] = slice {
1288 Some(first)
1289 } else {
1290 None
1291 }
1292}
1293
1294/// A const equivalent of
1295/// [`<[T]>::last_mut`](https://doc.rust-lang.org/std/primitive.slice.html#method.last_mut)
1296///
1297/// # Const stabilization
1298///
1299/// The equivalent std function was const-stabilized in Rust 1.83.0.
1300///
1301/// # Example
1302///
1303/// ```rust
1304/// use konst::slice;
1305///
1306/// assert_eq!(slice::last_mut(&mut [3, 5, 8]), Some(&mut 8));
1307///
1308/// assert_eq!(slice::last_mut(&mut [3, 5]), Some(&mut 5));
1309///
1310/// assert_eq!(slice::last_mut(&mut [3]), Some(&mut 3));
1311///
1312/// assert_eq!(slice::last_mut::<u8>(&mut []), None);
1313///
1314/// ```
1315#[cfg(feature = "rust_1_83")]
1316#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))]
1317pub const fn last_mut<T>(slice: &mut [T]) -> Option<&mut T> {
1318 if let [.., last] = slice {
1319 Some(last)
1320 } else {
1321 None
1322 }
1323}
1324
1325/// A const equivalent of
1326/// [`<[T]>::split_first_mut`
1327/// ](https://doc.rust-lang.org/std/primitive.slice.html#method.split_first_mut)
1328///
1329/// # Const stabilization
1330///
1331/// The equivalent std function was const-stabilized in Rust 1.83.0.
1332///
1333/// # Example
1334///
1335/// ```rust
1336/// use konst::slice;
1337///
1338/// assert_eq!(slice::split_first_mut(&mut [5, 8, 13, 21]), Some((&mut 5, &mut [8, 13, 21][..])));
1339/// assert_eq!(slice::split_first_mut(&mut [8, 13, 21]), Some((&mut 8, &mut [13, 21][..])));
1340/// assert_eq!(slice::split_first_mut(&mut [13, 21]), Some((&mut 13, &mut [21][..])));
1341/// assert_eq!(slice::split_first_mut(&mut [21]), Some((&mut 21, &mut [][..])));
1342/// assert_eq!(slice::split_first_mut::<()>(&mut []), None);
1343///
1344/// ```
1345///
1346#[cfg(feature = "rust_1_83")]
1347#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))]
1348pub const fn split_first_mut<T>(slice: &mut [T]) -> Option<(&mut T, &mut [T])> {
1349 if let [first, rem @ ..] = slice {
1350 Some((first, rem))
1351 } else {
1352 None
1353 }
1354}
1355
1356/// A const equivalent of
1357/// [`<[T]>::split_last_mut`
1358/// ](https://doc.rust-lang.org/std/primitive.slice.html#method.split_last_mut)
1359///
1360/// # Const stabilization
1361///
1362/// The equivalent std function was const-stabilized in Rust 1.83.0.
1363///
1364/// # Example
1365///
1366/// ```rust
1367/// use konst::slice;
1368///
1369/// assert_eq!(slice::split_last_mut(&mut [8, 13, 21, 5]), Some((&mut 5, &mut [8, 13, 21][..])));
1370/// assert_eq!(slice::split_last_mut(&mut [13, 21, 8]), Some((&mut 8, &mut [13, 21][..])));
1371/// assert_eq!(slice::split_last_mut(&mut [21, 13]), Some((&mut 13, &mut [21][..])));
1372/// assert_eq!(slice::split_last_mut(&mut [21]), Some((&mut 21, &mut [][..])));
1373/// assert_eq!(slice::split_last_mut::<()>(&mut []), None);
1374///
1375/// ```
1376///
1377#[cfg(feature = "rust_1_83")]
1378#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_83")))]
1379pub const fn split_last_mut<T>(slice: &mut [T]) -> Option<(&mut T, &mut [T])> {
1380 if let [rem @ .., last] = slice {
1381 Some((last, rem))
1382 } else {
1383 None
1384 }
1385}