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}