devela/sys/mem/slice/
namespace.rs

1// devela::sys::mem::slice::wrapper
2//
3//! Defines the [`Slice`] namespace.
4//
5// TODO:
6// - unchecked subslicing.
7// - saturating subslicing.
8// - first_chunk_padded
9
10use crate::Compare;
11use core::slice::{from_mut, from_ref};
12#[allow(unused_imports, reason = "unsafe feature-gated")]
13use core::slice::{from_raw_parts, from_raw_parts_mut};
14
15#[doc = crate::TAG_NAMESPACE!()]
16/// Slice-related operations, most of them *const*.
17///
18/// It is designed as a utility namespace and does not hold or wrap data itself.
19/// Instead, it operates on slices provided directly as arguments to its static methods.
20///
21// TODO: # Methods
22// - namespaced from core::slice.
23// - shared subslicing.
24// - exclusive subslicing.
25// - splitting.
26/// See also: [`ExtSlice`][crate::ExtSlice], [`Mem`][crate::Mem], [`Ptr`][crate::Ptr].
27pub struct Slice<T>(crate::PhantomData<T>);
28
29/// # `core::slice` namespaced methods
30impl<T> Slice<T> {
31    /// Converts a reference to `T` into a slice of length 1 (without copying).
32    ///
33    /// See `core::slice::`[`from_ref`].
34    #[must_use]
35    pub const fn from_ref(s: &T) -> &[T] {
36        from_ref(s)
37    }
38
39    /// Converts a reference to `T` into a slice of length 1 (without copying).
40    ///
41    /// See `core::slice::`[`from_mut`].
42    #[must_use]
43    pub const fn from_mut(s: &mut T) -> &mut [T] {
44        from_mut(s)
45    }
46
47    /// Forms a shared slice from a pointer and a length.
48    ///
49    /// # Safety
50    /// See `core::slice::`[`from_raw_parts`]
51    ///
52    /// See also `Ptr::`[`slice_from_raw_parts`][crate::Ptr::slice_from_raw_parts].
53    #[cfg_attr(feature = "nightly_doc", doc(cfg(unsafe··)))]
54    #[cfg(all(not(feature = "safe_mem"), unsafe··))]
55    pub const unsafe fn from_raw_parts<'a>(data: *const T, len: usize) -> &'a [T] {
56        // SAFETY: Caller must uphold the safety contract.
57        unsafe { from_raw_parts(data, len) }
58    }
59
60    /// Forms an exclusive slice from a pointer and a length.
61    ///
62    /// # Safety
63    /// See `core::slice::`[`from_raw_parts_mut`].
64    ///
65    /// See also `Ptr::`[`slice_from_raw_parts_mut`][crate::Ptr::slice_from_raw_parts_mut].
66    #[cfg_attr(feature = "nightly_doc", doc(cfg(unsafe··)))]
67    #[cfg(all(not(feature = "safe_mem"), unsafe··))]
68    pub const unsafe fn from_raw_parts_mut<'a>(data: *mut T, len: usize) -> &'a mut [T] {
69        // SAFETY: Caller must uphold the safety contract.
70        unsafe { from_raw_parts_mut(data, len) }
71    }
72}
73
74/// # Methods for shared subslicing using index-based splitting.
75impl<T> Slice<T> {
76    /* panicking */
77
78    /// Returns a subslice up to the given `end` index.
79    ///
80    /// Equivalent to `&slice[..end]`.
81    ///
82    /// # Panics
83    /// Panics if `end` > `slice.len()`.
84    #[must_use]
85    pub const fn range_to(slice: &[T], end: usize) -> &[T] {
86        slice.split_at(end).0
87    }
88    /// Returns a subslice starting from the given `start` index.
89    ///
90    /// Equivalent to `&slice[start..]`.
91    ///
92    /// # Panics
93    /// Panics if `start` > `slice.len()`.
94    #[must_use]
95    pub const fn range_from(slice: &[T], start: usize) -> &[T] {
96        slice.split_at(start).1
97    }
98    /// Returns a subslice from `start` (inclusive) to `end` (exclusive).
99    ///
100    /// Equivalent to `&slice[start..end]`.
101    ///
102    /// # Panics
103    /// Panics if `start` > len or `end` > `slice.len()`.
104    #[must_use]
105    pub const fn range(slice: &[T], start: usize, end: usize) -> &[T] {
106        slice.split_at(start).1.split_at(end - start).0
107    }
108
109    /// Returns the first `n` elements of the slice.
110    ///
111    /// Equivalent to `&slice[..n]`.
112    ///
113    /// # Panics
114    /// Panics if `n` > `slice.len()`.
115    #[must_use]
116    pub const fn take_first(slice: &[T], n: usize) -> &[T] {
117        slice.split_at(n).0
118    }
119    /// Returns the last `n` elements of the slice.
120    ///
121    /// Equivalent to `&slice[slice.len() - n..]`.
122    ///
123    /// # Panics
124    /// Panics if `n` > `slice.len()`.
125    #[must_use]
126    pub const fn take_last(slice: &[T], n: usize) -> &[T] {
127        slice.split_at(slice.len() - n).1
128    }
129    /// Returns the slice omitting the last `n` elements.
130    ///
131    /// Equivalent to `&slice[..slice.len() - n]`.
132    ///
133    /// # Panics
134    /// Panics if `n` > `slice.len()`.
135    #[must_use]
136    pub const fn take_omit_last(slice: &[T], n: usize) -> &[T] {
137        slice.split_at(slice.len() - n).0
138    }
139
140    /* Checked */
141
142    /// Returns a subslice up to the given `end` index.
143    ///
144    /// Equivalent to `&slice[..end]`.
145    ///
146    /// Returns `None` if `end` > `slice.len()`.
147    #[must_use]
148    pub const fn range_to_checked(slice: &[T], end: usize) -> Option<&[T]> {
149        match slice.split_at_checked(end) {
150            Some((subslice, _)) => Some(subslice),
151            None => None,
152        }
153    }
154    /// Returns a subslice starting from the given `start` index.
155    ///
156    /// Equivalent to `&slice[start..]`.
157    ///
158    /// Returns `None` if `start` > `slice.len()`.
159    #[must_use]
160    pub const fn range_from_checked(slice: &[T], start: usize) -> Option<&[T]> {
161        match slice.split_at_checked(start) {
162            Some((_, subslice)) => Some(subslice),
163            None => None,
164        }
165    }
166    /// Returns a subslice from `start` (inclusive) to `end` (exclusive).
167    ///
168    /// Equivalent to `&slice[start..end]`.
169    ///
170    /// Returns `None` if `start` > `slice.len()` or `end` > `slice.len()`.
171    ///
172    /// # Features
173    /// This method makes use of of the `unsafe_slice` feature is enabled.
174    #[must_use]
175    pub const fn range_checked(slice: &[T], start: usize, end: usize) -> Option<&[T]> {
176        if start <= end && end <= slice.len() {
177            #[cfg(any(feature = "safe_mem", not(feature = "unsafe_slice")))]
178            return Some(slice.split_at(start).1.split_at(end - start).0);
179            #[cfg(all(not(feature = "safe_mem"), feature = "unsafe_slice"))]
180            // SAFETY: `start` and `end` are checked to be within bounds and valid
181            Some(unsafe { slice.split_at_unchecked(start).1.split_at_unchecked(end - start).0 })
182        } else {
183            None
184        }
185    }
186
187    /// Returns the first `n` elements of the slice.
188    ///
189    /// Equivalent to `&slice[..n]`.
190    ///
191    /// Returns `None` if `n` > `slice.len()`.
192    #[must_use]
193    pub const fn take_first_checked(slice: &[T], n: usize) -> Option<&[T]> {
194        match slice.split_at_checked(n) {
195            Some((subslice, _)) => Some(subslice),
196            None => None,
197        }
198    }
199    /// Returns the last `n` elements of the slice.
200    ///
201    /// Equivalent to `&slice[slice.len() - n..]`.
202    ///
203    /// Returns `None` if `n` > `slice.len()`.
204    ///
205    /// # Features
206    /// This method makes use of of the `unsafe_slice` feature is enabled.
207    #[must_use]
208    pub const fn take_last_checked(slice: &[T], n: usize) -> Option<&[T]> {
209        match slice.len().checked_sub(n) {
210            Some(index) => {
211                #[cfg(any(feature = "safe_mem", not(feature = "unsafe_slice")))]
212                return Some(slice.split_at(index).1);
213                #[cfg(all(not(feature = "safe_mem"), feature = "unsafe_slice"))]
214                // SAFETY: `n` is checked to be within bounds and valid
215                return Some(unsafe { slice.split_at_unchecked(index).1 });
216            }
217            None => None,
218        }
219    }
220    /// Returns the slice omitting the last `n` elements.
221    ///
222    /// Equivalent to `&slice[..slice.len() - n]`.
223    ///
224    /// Returns `None` if `n` > `slice.len()`.
225    ///
226    /// # Features
227    /// This method makes use of of the `unsafe_slice` feature is enabled.
228    #[must_use]
229    pub const fn take_omit_last_checked(slice: &[T], n: usize) -> Option<&[T]> {
230        match slice.len().checked_sub(n) {
231            Some(index) => {
232                #[cfg(any(feature = "safe_mem", not(feature = "unsafe_slice")))]
233                return Some(slice.split_at(index).0);
234                #[cfg(all(not(feature = "safe_mem"), feature = "unsafe_slice"))]
235                // SAFETY: `n` is checked to be within bounds and valid
236                return Some(unsafe { slice.split_at_unchecked(index).0 });
237            }
238            None => None,
239        }
240    }
241}
242
243/// # Methods for exclusive subslicing using index-based splitting.
244impl<T> Slice<T> {
245    /* panicking */
246
247    /// Returns an exclusive subslice up to the given `end` index.
248    ///
249    /// Equivalent to `&mut slice[..end]`.
250    ///
251    /// # Panics
252    /// Panics if `end` > `slice.len()`.
253    #[must_use]
254    pub const fn range_to_mut(slice: &mut [T], end: usize) -> &mut [T] {
255        slice.split_at_mut(end).0
256    }
257    /// Returns an exclusive subslice starting from the given `start` index.
258    ///
259    /// Equivalent to `&mut slice[start..]`.
260    ///
261    /// # Panics
262    /// Panics if `start` > `slice.len()`.
263    #[must_use]
264    pub const fn range_from_mut(slice: &mut [T], start: usize) -> &mut [T] {
265        slice.split_at_mut(start).1
266    }
267    /// Returns an exclusive subslice from `start` (inclusive) to `end` (exclusive).
268    ///
269    /// Equivalent to `&mut slice[start..end]`.
270    ///
271    /// # Panics
272    /// Panics if `start` > `slice.len()` or `end` > `slice.len()`.
273    #[must_use]
274    pub const fn range_mut(slice: &mut [T], start: usize, end: usize) -> &mut [T] {
275        slice.split_at_mut(start).1.split_at_mut(end - start).0
276    }
277
278    /// Returns the first `n` elements of the exclusive slice.
279    ///
280    /// Equivalent to `&mut slice[..n]`.
281    ///
282    /// # Panics
283    /// Panics if `n` > `slice.len()`.
284    #[must_use]
285    pub const fn take_first_mut(slice: &mut [T], n: usize) -> &mut [T] {
286        slice.split_at_mut(n).0
287    }
288    /// Returns the last `n` elements of the exclusive slice.
289    ///
290    /// Equivalent to `&mut slice[slice.len() - n..]`.
291    ///
292    /// # Panics
293    /// Panics if `n` > `slice.len()`.
294    #[must_use]
295    pub const fn take_last_mut(slice: &mut [T], n: usize) -> &mut [T] {
296        slice.split_at_mut(slice.len() - n).1
297    }
298    /// Returns the exclusive slice omitting the last `n` elements.
299    ///
300    /// Equivalent to `&mut slice[..slice.len() - n]`.
301    ///
302    /// # Panics
303    /// Panics if `n` > `slice.len()`.
304    #[must_use]
305    pub const fn take_omit_last_mut(slice: &mut [T], n: usize) -> &mut [T] {
306        slice.split_at_mut(slice.len() - n).0
307    }
308
309    /* Checked */
310
311    /// Returns a subslice up to the given `end` index.
312    ///
313    /// Equivalent to `&mut slice[..end]`.
314    ///
315    /// Returns `None` if `end` > `slice.len()`.
316    #[must_use]
317    pub const fn range_to_mut_checked(slice: &mut [T], end: usize) -> Option<&mut [T]> {
318        match slice.split_at_mut_checked(end) {
319            Some((subslice, _)) => Some(subslice),
320            None => None,
321        }
322    }
323    /// Returns a subslice starting from the given `start` index.
324    ///
325    /// Equivalent to `&mut slice[start..]`.
326    ///
327    /// Returns `None` if `start` > `slice.len()`.
328    #[must_use]
329    pub const fn range_from_mut_checked(slice: &mut [T], start: usize) -> Option<&mut [T]> {
330        match slice.split_at_mut_checked(start) {
331            Some((_, subslice)) => Some(subslice),
332            None => None,
333        }
334    }
335    /// Returns a subslice from `start` (inclusive) to `end` (exclusive).
336    ///
337    /// Equivalent to `&mut slice[start..end]`.
338    ///
339    /// Returns `None` if `start` > `slice.len()` or `end` > `slice.len()`.
340    ///
341    /// # Features
342    /// This method makes use of of the `unsafe_slice` feature is enabled.
343    #[must_use]
344    pub const fn range_mut_checked(slice: &mut [T], start: usize, end: usize) -> Option<&mut [T]> {
345        if start <= end && end <= slice.len() {
346            #[cfg(any(feature = "safe_mem", not(feature = "unsafe_slice")))]
347            return Some(slice.split_at_mut(start).1.split_at_mut(end - start).0);
348            #[cfg(all(not(feature = "safe_mem"), feature = "unsafe_slice"))]
349            // SAFETY: `start` and `end` are checked to be within bounds and valid
350            Some(unsafe {
351                slice.split_at_mut_unchecked(start).1.split_at_mut_unchecked(end - start).0
352            })
353        } else {
354            None
355        }
356    }
357
358    /// Returns the first `n` elements of the slice.
359    ///
360    /// Equivalent to `&mut slice[..n]`.
361    ///
362    /// Returns `None` if `n` > `slice.len()`.
363    #[must_use]
364    pub const fn take_first_mut_checked(slice: &mut [T], n: usize) -> Option<&mut [T]> {
365        match slice.split_at_mut_checked(n) {
366            Some((subslice, _)) => Some(subslice),
367            None => None,
368        }
369    }
370    /// Returns the last `n` elements of the slice.
371    ///
372    /// Equivalent to `&mut slice[slice.len() - n..]`.
373    ///
374    /// Returns `None` if `n` > `slice.len()`.
375    ///
376    /// # Features
377    /// This method makes use of of the `unsafe_slice` feature is enabled.
378    #[must_use]
379    pub const fn take_last_mut_checked(slice: &mut [T], n: usize) -> Option<&mut [T]> {
380        match slice.len().checked_sub(n) {
381            Some(index) => {
382                #[cfg(any(feature = "safe_mem", not(feature = "unsafe_slice")))]
383                return Some(slice.split_at_mut(index).1);
384                #[cfg(all(not(feature = "safe_mem"), feature = "unsafe_slice"))]
385                // SAFETY: `n` is checked to be within bounds and valid
386                return Some(unsafe { slice.split_at_mut_unchecked(index).1 });
387            }
388            None => None,
389        }
390    }
391    /// Returns the slice omitting the last `n` elements.
392    ///
393    /// Equivalent to `&mut slice[..slice.len() - n]`.
394    ///
395    /// Returns `None` if `n` > `slice.len()`.
396    ///
397    /// # Features
398    /// This method makes use of of the `unsafe_slice` feature is enabled.
399    #[must_use]
400    pub const fn take_omit_last_mut_checked(slice: &mut [T], n: usize) -> Option<&mut [T]> {
401        match slice.len().checked_sub(n) {
402            Some(index) => {
403                #[cfg(any(feature = "safe_mem", not(feature = "unsafe_slice")))]
404                return Some(slice.split_at_mut(index).0);
405                #[cfg(all(not(feature = "safe_mem"), feature = "unsafe_slice"))]
406                // SAFETY: `n` is checked to be within bounds and valid
407                return Some(unsafe { slice.split_at_mut_unchecked(index).0 });
408            }
409            None => None,
410        }
411    }
412}
413
414/// # Methods for splitting.
415impl<T> Slice<T> {
416    /* left split */
417
418    /// Returns the leftmost sub-`slice` with the given maximum `len`.
419    ///
420    /// If `len > self.len()` it returns the full slice.
421    ///
422    /// # Example
423    /// ```
424    /// # use devela::Slice;
425    /// let v = [1, 2, 3, 4, 5, 6];
426    /// assert_eq!(Slice::lsplit(&v, 3), &[1, 2, 3]);
427    /// assert_eq!(Slice::lsplit(&v, 0), &[] as &[i32]);
428    /// assert_eq!(Slice::lsplit(&v, 10), &[1, 2, 3, 4, 5, 6]);
429    /// ```
430    pub const fn lsplit(slice: &[T], len: usize) -> &[T] {
431        let end_idx = Compare(len).clamp(0, slice.len());
432        let (left, _) = slice.split_at(end_idx);
433        left
434    }
435
436    /// Returns the leftmost exclusive sub-`slice` with the given maximum `len`.
437    ///
438    /// If `left_len > slice.len()` it returns the full slice.
439    ///
440    /// # Example
441    /// ```
442    /// # use devela::Slice;
443    /// let mut v = [1, 2, 3, 4, 5, 6];
444    /// assert_eq!(Slice::lsplit_mut(&mut v, 3), &mut [1, 2, 3]);
445    /// assert_eq!(Slice::lsplit_mut(&mut v, 0), &mut [] as &mut [i32]);
446    /// assert_eq!(Slice::lsplit_mut(&mut v, 10), &mut [1, 2, 3, 4, 5, 6]);
447    /// ```
448    /// See also [`Slice::lsplit_mut`].
449    pub const fn lsplit_mut(slice: &mut [T], len: usize) -> &mut [T] {
450        let end_idx = Compare(len).clamp(0, slice.len());
451        let (left, _) = slice.split_at_mut(end_idx);
452        left
453    }
454
455    /* right split */
456
457    /// Returns the rightmost sub-`slice` with the given maximum `len`.
458    ///
459    /// If `left_len > slice.len()` it returns the full slice.
460    ///
461    /// # Example
462    /// ```
463    /// # use devela::Slice;
464    /// let v = [1, 2, 3, 4, 5, 6];
465    /// assert_eq!(Slice::rsplit(&v, 3), &[4, 5, 6]);
466    /// assert_eq!(Slice::rsplit(&v, 0), &[] as &[i32]);
467    /// assert_eq!(Slice::rsplit(&v, 10), &[1, 2, 3, 4, 5, 6]);
468    /// ```
469    #[must_use]
470    pub const fn rsplit(slice: &[T], len: usize) -> &[T] {
471        let start_idx = slice.len().saturating_sub(len);
472        let (_, right) = slice.split_at(start_idx);
473        right
474    }
475
476    /// Returns the rightmost mutable sub-`slice` with the given maximum `len`.
477    ///
478    /// If `left_len > slice.len()` it returns the full slice.
479    ///
480    /// # Example
481    /// ```
482    /// # use devela::Slice;
483    /// let mut v = [1, 2, 3, 4, 5, 6];
484    /// assert_eq!(Slice::rsplit_mut(&mut v, 3), &mut [4, 5, 6]);
485    /// assert_eq!(Slice::rsplit_mut(&mut v, 0), &mut [] as &mut [i32]);
486    /// assert_eq!(Slice::rsplit_mut(&mut v, 10), &mut [1, 2, 3, 4, 5, 6]);
487    /// ```
488    /// See also [`Slice::lsplit_mut`].
489    #[must_use]
490    pub const fn rsplit_mut(slice: &mut [T], len: usize) -> &mut [T] {
491        let start_idx = slice.len().saturating_sub(len);
492        let (_, right) = slice.split_at_mut(start_idx);
493        right
494    }
495
496    /* middle split left biased */
497
498    /// Returns the middle sub-`slice` with the given maximum `len` and a left bias.
499    ///
500    /// In case of a non-perfect middle split, it will have one character more
501    /// on the left.
502    ///
503    /// If `len > slice.len()` returns the full `slice`.
504    ///
505    /// # Example
506    /// ```
507    /// # use devela::Slice;
508    /// let v = [1, 2, 3, 4, 5, 6];
509    /// assert_eq!(Slice::msplit_left(&v, 0), &[] as &[i32]);
510    /// assert_eq!(Slice::msplit_left(&v, 1), &[3]);
511    /// assert_eq!(Slice::msplit_left(&v, 2), &[3, 4]);
512    /// assert_eq!(Slice::msplit_left(&v, 3), &[2, 3, 4]);
513    /// assert_eq!(Slice::msplit_left(&v, 4), &[2, 3, 4, 5]);
514    /// assert_eq!(Slice::msplit_left(&v, 5), &[1, 2, 3, 4, 5]);
515    /// assert_eq!(Slice::msplit_left(&v, 10), &[1, 2, 3, 4, 5, 6]);
516    /// ```
517    /// See also [`Slice::msplit_right`].
518    #[must_use]
519    pub const fn msplit_left(slice: &[T], len: usize) -> &[T] {
520        let mid_idx = slice.len() / 2;
521        let half_len = len / 2;
522        let start_idx = mid_idx.saturating_sub(half_len + (len % 2));
523        let end_idx = Compare(mid_idx + half_len).min(slice.len());
524        let (_, right) = slice.split_at(start_idx);
525        let (middle, _) = right.split_at(end_idx - start_idx);
526        middle
527    }
528
529    /// Returns the middle exclusive sub-`slice` with the given maximum `len` and a
530    /// left bias.
531    ///
532    /// In case of a non-perfect middle split, it will have one character more
533    /// on the left.
534    ///
535    /// If `len > slice.len()` returns the full `slice`.
536    ///
537    /// # Example
538    /// ```
539    /// # use devela::Slice;
540    /// let mut v = [1, 2, 3, 4, 5, 6];
541    /// assert_eq!(Slice::msplit_left_mut(&mut v, 0), &mut [] as &mut [i32]);
542    /// assert_eq!(Slice::msplit_left_mut(&mut v, 1), &mut [3]);
543    /// assert_eq!(Slice::msplit_left_mut(&mut v, 2), &mut [3, 4]);
544    /// assert_eq!(Slice::msplit_left_mut(&mut v, 3), &mut [2, 3, 4]);
545    /// assert_eq!(Slice::msplit_left_mut(&mut v, 4), &mut [2, 3, 4, 5]);
546    /// assert_eq!(Slice::msplit_left_mut(&mut v, 5), &mut [1, 2, 3, 4, 5]);
547    /// assert_eq!(Slice::msplit_left_mut(&mut v, 10), &mut [1, 2, 3, 4, 5, 6]);
548    /// ```
549    /// See also [`Slice::msplit_right_mut`].
550    #[must_use]
551    pub const fn msplit_left_mut(slice: &mut [T], len: usize) -> &mut [T] {
552        let mid_idx = slice.len() / 2;
553        let half_len = len / 2;
554        let start_idx = mid_idx.saturating_sub(half_len + (len % 2));
555        let end_idx = Compare(mid_idx + half_len).min(slice.len());
556        let (_, right) = slice.split_at_mut(start_idx);
557        let (middle, _) = right.split_at_mut(end_idx - start_idx);
558        middle
559    }
560
561    /* middle split right biased */
562
563    /// Returns the middle sub-`slice` with the given maximum `len` and a right bias.
564    ///
565    /// In case of a non-perfect middle split, it will have one character more
566    /// on the right.
567    ///
568    /// If `len > slice.len()` returns the full `slice`.
569    ///
570    /// # Example
571    /// ```
572    /// # use devela::Slice;
573    /// let v = [1, 2, 3, 4, 5, 6];
574    /// assert_eq!(Slice::msplit_right(&v, 0), &[] as &[i32]);
575    /// assert_eq!(Slice::msplit_right(&v, 1), &[4]);
576    /// assert_eq!(Slice::msplit_right(&v, 2), &[3, 4]);
577    /// assert_eq!(Slice::msplit_right(&v, 3), &[3, 4, 5]);
578    /// assert_eq!(Slice::msplit_right(&v, 4), &[2, 3, 4, 5]);
579    /// assert_eq!(Slice::msplit_right(&v, 5), &[2, 3, 4, 5, 6]);
580    /// assert_eq!(Slice::msplit_right(&v, 10), &[1, 2, 3, 4, 5, 6]);
581    /// ```
582    /// See also [`Slice::msplit_left`].
583    #[must_use]
584    pub const fn msplit_right(slice: &[T], len: usize) -> &[T] {
585        let mid_idx = slice.len() / 2;
586        let half_len = len / 2;
587        let start_idx = mid_idx.saturating_sub(half_len);
588        let end_idx = Compare(mid_idx + half_len + (len % 2)).min(slice.len());
589        let (_, right) = slice.split_at(start_idx);
590        let (middle, _) = right.split_at(end_idx - start_idx);
591        middle
592    }
593
594    /// Returns the middle exclusive sub-`slice` with the given maximum `len` and a
595    /// right bias.
596    ///
597    /// In case of a non-perfect middle split, it will have one character more
598    /// on the right.
599    ///
600    /// If `len > slice.len()` returns the full `slice`.
601    /// # Example
602    /// ```
603    /// # use devela::Slice;
604    /// let mut v = [1, 2, 3, 4, 5, 6];
605    /// assert_eq!(Slice::msplit_right_mut(&mut v, 0), &mut [] as &mut[i32]);
606    /// assert_eq!(Slice::msplit_right_mut(&mut v, 1), &mut [4]);
607    /// assert_eq!(Slice::msplit_right_mut(&mut v, 2), &mut [3, 4]);
608    /// assert_eq!(Slice::msplit_right_mut(&mut v, 3), &mut [3, 4, 5]);
609    /// assert_eq!(Slice::msplit_right_mut(&mut v, 4), &mut [2, 3, 4, 5]);
610    /// assert_eq!(Slice::msplit_right_mut(&mut v, 5), &mut [2, 3, 4, 5, 6]);
611    /// assert_eq!(Slice::msplit_right_mut(&mut v, 10), &mut [1, 2, 3, 4, 5, 6]);
612    /// ```
613    /// See also [`Slice::msplit_left_mut`].
614    #[must_use]
615    pub const fn msplit_right_mut(slice: &mut [T], len: usize) -> &mut [T] {
616        let mid_idx = slice.len() / 2;
617        let half_len = len / 2;
618        let start_idx = mid_idx.saturating_sub(half_len);
619        let end_idx = Compare(mid_idx + half_len + (len % 2)).min(slice.len());
620        let (_, right) = slice.split_at_mut(start_idx);
621        let (middle, _) = right.split_at_mut(end_idx - start_idx);
622        middle
623    }
624}
625
626/// # Methods for slices of bytes.
627// TODO: add from [u8] https://doc.rust-lang.org/stable/std/primitive.slice.html#impl-%5Bu8%5D
628//
629// - is_ascii, trim_ascii?
630impl Slice<u8> {
631    /// Copies the `src` slice into `dst` in compile-time.
632    pub const fn const_copy<const N: usize>(src: &[u8; N], dst: &mut [u8; N]) {
633        let mut i = 0;
634        while i < N {
635            dst[i] = src[i];
636            i += 1;
637        }
638    }
639    /// Returns a subslice without the given leading `byte`s.
640    #[must_use]
641    pub const fn trim_leading_bytes(slice: &[u8], byte: u8) -> &[u8] {
642        let mut start = 0;
643        while start < slice.len() && slice[start] == byte {
644            start += 1;
645        }
646        slice.split_at(start).1 // == &slice[start..]
647    }
648
649    /// Replaces the `old` leading byte with a `new` byte.
650    pub const fn replace_leading_bytes(slice: &mut [u8], old: u8, new: u8) {
651        let mut start = 0;
652        while start < slice.len() && slice[start] == old {
653            slice[start] = new;
654            start += 1;
655        }
656    }
657}
658
659/// Helper for implementing slice operations for primitives.
660macro_rules! impl_prim {
661    () => {
662        impl_prim![
663            u8, u16, u32, u64, u128, usize,
664            i8, i16, i32, i64, i128, isize,
665            f32, f64,
666            bool, char
667        ];
668        #[cfg(feature = "nightly_float")]
669        impl_prim![f16, f128];
670    };
671    ($($t:ty),+) => { $( impl_prim![@$t]; )+ };
672    (@$t:ty) => {
673        impl Slice<$t> {
674            /// Checks the equality of two slices of primitives in compile-time.
675            #[must_use]
676            pub const fn eq(a: &[$t], b: &[$t]) -> bool {
677                if a.len() != b.len() { return false; }
678                let mut i = 0;
679                while i < a.len() {
680                    if a[i] != b[i] { return false; }
681                    i += 1;
682                }
683                true
684            }
685        }
686    };
687}
688impl_prim!();
689
690impl Slice<&str> {
691    /// Checks the equality of two string slices in compile-time.
692    #[must_use]
693    pub const fn eq(a: &str, b: &str) -> bool {
694        Slice::<u8>::eq(a.as_bytes(), b.as_bytes())
695    }
696}
697impl Slice<&[&str]> {
698    /// Checks the equality of two slices of string slices in compile-time.
699    #[must_use]
700    pub const fn eq(a: &[&str], b: &[&str]) -> bool {
701        if a.len() != b.len() {
702            return false;
703        }
704        let mut i = 0;
705        while i < a.len() {
706            if !Slice::<&str>::eq(a[i], b[i]) {
707                return false;
708            }
709            i += 1;
710        }
711        true
712    }
713}