devela/sys/mem/slice/
ext.rs

1// devela::sys::mem::slice::ext
2//
3//! Defines [`ExtSlice`].
4//
5
6use super::Slice;
7#[cfg(feature = "alloc")]
8use crate::data::Vec;
9
10/// Marker trait to prevent downstream implementations of the [`ExtSlice`] trait.
11trait Sealed {}
12impl<T> Sealed for [T] {}
13impl<T> Sealed for &[T] {}
14impl<T> Sealed for &mut [T] {}
15impl<T, const LEN: usize> Sealed for [T; LEN] {}
16#[cfg(feature = "alloc")]
17impl<T> Sealed for Vec<T> {}
18
19#[doc = crate::TAG_NAMESPACE!()]
20/// Extension trait providing additional methods for [`&[T]`][slice].
21///
22/// This trait is sealed and cannot be implemented for any other type.
23///
24/// See also [`Slice`][crate::Slice] for *const* methods.
25#[cfg_attr(feature = "nightly_doc", doc(notable_trait))]
26#[expect(private_bounds, reason = "Sealed")]
27pub trait ExtSlice<T>: Sealed {
28    /* split */
29
30    /// Returns a left subslice of `slice` with the given maximum `len`.
31    ///
32    /// If `left_len > slice.len()` it returns the full slice.
33    ///
34    /// See also [`Slice::lsplit`] for the standalone `const` version.
35    #[must_use]
36    fn slice_lsplit(&self, len: usize) -> &[T];
37
38    /// Returns a right subslice of `slice` with the given maximum `len`.
39    ///
40    /// If `left_len > slice.len()` it returns the full slice.
41    ///
42    /// See also [`Slice::rsplit`] for the standalone `const` version.
43    #[must_use]
44    fn slice_rsplit(&self, len: usize) -> &[T];
45
46    /// Returns a middle subslice of `slice` with the given maximum `len`
47    /// and a left bias.
48    ///
49    /// In case of a non-perfect middle split, it will have one character more
50    /// on the left.
51    ///
52    /// If `len > slice.len()` returns the full `slice`.
53    ///
54    /// See also [`Slice::msplit_left`] for the standalone `const` version.
55    #[must_use]
56    fn slice_msplit_left(&self, len: usize) -> &[T];
57
58    /// Returns a middle subslice of `slice` with the given maximum `len`
59    /// and a right bias.
60    ///
61    /// In case of a non-perfect middle split, it will have one character more
62    /// on the right.
63    ///
64    /// If `len > slice.len()` returns the full `slice`.
65    ///
66    /// See also [`Slice::msplit_right`] for the standalone `const` version.
67    #[must_use]
68    fn slice_msplit_right(&self, len: usize) -> &[T];
69
70    /* convert */
71
72    /// Converts `&[T]` to `[U; N]` when `U` implements `From<T>`.
73    ///
74    /// # Panics
75    /// Panics if the length of the slice is less than the length of the array.
76    /// # Examples
77    /// ```
78    /// # use devela::ExtSlice;
79    /// assert_eq![[1_u16, 2, 3], [1_u8, 2, 3].slice_into_array::<u16, 3>()];
80    /// assert_eq![[1_u16, 2, 3], [1_u8, 2, 3].slice_into_array::<u16, 3>()];
81    /// ```
82    /// # Features
83    /// If the `unsafe_array` feature is enabled it uses `MaybeUninit` to improve performance.
84    #[must_use]
85    // IMPROVE make a try_slice_into_array version:
86    // WAIT: [try_array_from_fn](https://github.com/rust-lang/rust/issues/89379)
87    // - https://doc.rust-lang.org/nightly/core/array/fn.try_from_fn.html
88    fn slice_into_array<U, const N: usize>(&self) -> [U; N]
89    where
90        T: Clone,
91        U: From<T>;
92
93    /// Converts `&[T]` to `Vec<U>` when `U` implements `From<T>`.
94    /// # Examples
95    /// ```
96    /// # use devela::ExtSlice;
97    /// assert_eq![vec![1_i16, 2, 3], [1_u8, 2, 3].slice_into_vec::<i16>()];
98    /// assert_eq![vec![1_i16, 2, 3], [1_u8, 2, 3].slice_into_vec::<i16>()];
99    /// ```
100    #[must_use]
101    #[cfg(feature = "alloc")]
102    #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "alloc")))]
103    fn slice_into_vec<U>(&self) -> Vec<U>
104    where
105        T: Clone,
106        U: From<T>;
107
108    /// Tries to convert `&[T]` to `Vec<U>` when `U` implements `TryFrom<T>`.
109    /// # Examples
110    /// ```
111    /// # use devela::ExtSlice;
112    /// assert_eq![Ok(vec![1_i32, 2, 3]), [1_i64, 2, 3].slice_try_into_vec()];
113    /// assert_eq![Ok(vec![1_i32, 2, 3]), [1_i64, 2, 3].slice_try_into_vec::<_, i32>()];
114    /// ```
115    #[cfg(feature = "alloc")]
116    #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "alloc")))]
117    fn slice_try_into_vec<E, U>(&self) -> Result<Vec<U>, E>
118    where
119        T: Clone,
120        U: TryFrom<T, Error = E>;
121}
122
123#[doc = crate::TAG_NAMESPACE!()]
124/// Extension trait providing additional methods for [`&mut [T]`][slice].
125///
126/// This trait is sealed and cannot be implemented for any other type.
127///
128/// See also [`Slice`][crate::Slice] for *const* methods.
129#[cfg_attr(feature = "nightly_doc", doc(notable_trait))]
130pub trait ExtSliceMut<T>: ExtSlice<T> {
131    /* split */
132
133    /// Returns a mutable left subslice of `slice` with the given maximum `len`.
134    ///
135    /// If `left_len > slice.len()` it returns the full slice.
136    #[must_use]
137    fn slice_lsplit_mut(&mut self, len: usize) -> &mut [T];
138
139    /// Returns a mutable right subslice of `slice` with the given maximum `len`.
140    ///
141    /// If `left_len > slice.len()` it returns the full slice.
142    #[must_use]
143    fn slice_rsplit_mut(&mut self, len: usize) -> &mut [T];
144
145    /// Returns a mutable middle subslice of `slice` with the given maximum `len`
146    /// and a left bias.
147    ///
148    /// In case of a non-perfect middle split, it will have one character more
149    /// on the left.
150    ///
151    /// If `len > slice.len()` returns the full `slice`.
152    #[must_use]
153    fn slice_msplit_left_mut(&mut self, len: usize) -> &mut [T];
154
155    /// Returns a mutable middle subslice of `slice` with the given maximum `len`
156    /// and a right bias.
157    ///
158    /// In case of a non-perfect middle split, it will have one character more
159    /// on the right.
160    ///
161    /// If `len > slice.len()` returns the full `slice`.
162    #[must_use]
163    fn slice_msplit_right_mut(&mut self, len: usize) -> &mut [T];
164}
165
166macro_rules! impl_ext_slice {
167    ($t:ty, for $for:ty, impl: $($impl:tt)*) => {
168        impl<$($impl)*> ExtSlice<$t> for $for {
169            /* split */
170
171            fn slice_lsplit(&self, len: usize) -> &[T] { Slice::lsplit(self, len) }
172            fn slice_rsplit(&self, len: usize) -> &[T] { Slice::rsplit(self, len) }
173            fn slice_msplit_left(&self, len: usize) -> &[T] { Slice::msplit_left(self, len) }
174            fn slice_msplit_right(&self, len: usize) -> &[T] { Slice::msplit_right(self, len) }
175
176            /* collection */
177
178            fn slice_into_array<U, const N: usize>(&self) -> [U; N] where T: Clone, U: From<T> {
179                if self.len() >= N {
180                    #[cfg(any(feature = "safe_data", not(feature = "unsafe_array")))]
181                    {
182                        let mut array: [U; N] = crate::array_from_fn(|i| U::from(self[i].clone()));
183                        for (i, item) in self.iter().take(N).enumerate() {
184                            array[i] = U::from(item.clone());
185                        }
186                        array
187                    }
188                    // SAFETY: we make sure of initializing every array element
189                    #[cfg(all(not(feature = "safe_data"), feature = "unsafe_array"))]
190                    {
191                        use crate::MaybeUninit;
192                        let mut array: [MaybeUninit<U>; N] =
193                            unsafe { MaybeUninit::uninit().assume_init() };
194                        for i in 0..N { array[i] = MaybeUninit::new(U::from(self[i].clone())); }
195                        array.map(|x| unsafe { x.assume_init() })
196                    }
197                } else {
198                    panic!("Slice length is less than the requested array size")
199                }
200            }
201            #[cfg(feature = "alloc")]
202            fn slice_into_vec<U>(&self) -> Vec<U> where T: Clone, U: From<T> {
203                self.iter().map(|t| U::from(t.clone())).collect::<Vec<_>>().into_iter().collect()
204            }
205            #[cfg(feature = "alloc")]
206            fn slice_try_into_vec<E, U>(&self) -> Result<Vec<U>, E>
207                where T: Clone, U: TryFrom<T, Error = E> {
208                    self
209                        // 1. Vec<Result<_>>:
210                        .iter()
211                        .map(|t| U::try_from(t.clone()))
212                        .collect::<Vec<_>>()
213                        // 2. Result<Vec<_>>:
214                        .into_iter()
215                        .collect::<Result<Vec<_>, _>>()
216            }
217        }
218    };
219    (mut: $t:ty, for $for:ty, impl: $($impl:tt)*) => {
220        impl_ext_slice![$t, for $for, impl: $($impl)*];
221
222        impl<$($impl)*> ExtSliceMut<$t> for $for {
223            /* split */
224
225            fn slice_lsplit_mut(&mut self, len: usize) -> &mut [T] { Slice::lsplit_mut(self, len) }
226            fn slice_rsplit_mut(&mut self, len: usize) -> &mut [T] { Slice::rsplit_mut(self, len) }
227            fn slice_msplit_left_mut(&mut self, len: usize) -> &mut [T] {
228                Slice::msplit_left_mut(self, len) }
229            fn slice_msplit_right_mut(&mut self, len: usize) -> &mut [T] {
230                Slice::msplit_right_mut(self, len) }
231        }
232    };
233}
234impl_ext_slice![mut: T, for [T], impl: T];
235impl_ext_slice![T, for &[T], impl: T];
236impl_ext_slice![mut: T, for &mut [T], impl: T];
237impl_ext_slice![mut: T, for [T; LEN], impl: T, const LEN: usize];
238#[cfg(feature = "alloc")]
239impl_ext_slice![mut: T, for Vec<T>, impl: T];