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];