core_simd/
swizzle.rs

1use crate::simd::{Mask, MaskElement, Simd, SimdElement};
2
3/// Constructs a new SIMD vector by copying elements from selected elements in other vectors.
4///
5/// When swizzling one vector, elements are selected like [`Swizzle::swizzle`].
6///
7/// When swizzling two vectors, elements are selected like [`Swizzle::concat_swizzle`].
8///
9/// # Examples
10///
11/// With a single SIMD vector, the const array specifies element indices in that vector:
12/// ```
13/// # #![feature(portable_simd)]
14/// # use core::simd::{u32x2, u32x4, simd_swizzle};
15/// let v = u32x4::from_array([10, 11, 12, 13]);
16///
17/// // Keeping the same size
18/// let r: u32x4 = simd_swizzle!(v, [3, 0, 1, 2]);
19/// assert_eq!(r.to_array(), [13, 10, 11, 12]);
20///
21/// // Changing the number of elements
22/// let r: u32x2 = simd_swizzle!(v, [3, 1]);
23/// assert_eq!(r.to_array(), [13, 11]);
24/// ```
25///
26/// With two input SIMD vectors, the const array specifies element indices in the concatenation of
27/// those vectors:
28/// ```
29/// # #![feature(portable_simd)]
30/// # #[cfg(feature = "as_crate")] use core_simd::simd;
31/// # #[cfg(not(feature = "as_crate"))] use core::simd;
32/// # use simd::{u32x2, u32x4, simd_swizzle};
33/// let a = u32x4::from_array([0, 1, 2, 3]);
34/// let b = u32x4::from_array([4, 5, 6, 7]);
35///
36/// // Keeping the same size
37/// let r: u32x4 = simd_swizzle!(a, b, [0, 1, 6, 7]);
38/// assert_eq!(r.to_array(), [0, 1, 6, 7]);
39///
40/// // Changing the number of elements
41/// let r: u32x2 = simd_swizzle!(a, b, [0, 4]);
42/// assert_eq!(r.to_array(), [0, 4]);
43/// ```
44#[allow(unused_macros)]
45pub macro simd_swizzle {
46    (
47        $vector:expr, $index:expr $(,)?
48    ) => {
49        {
50            use $crate::simd::Swizzle;
51            struct Impl;
52            impl Swizzle<{$index.len()}> for Impl {
53                const INDEX: [usize; {$index.len()}] = $index;
54            }
55            Impl::swizzle($vector)
56        }
57    },
58    (
59        $first:expr, $second:expr, $index:expr $(,)?
60    ) => {
61        {
62            use $crate::simd::Swizzle;
63            struct Impl;
64            impl Swizzle<{$index.len()}> for Impl {
65                const INDEX: [usize; {$index.len()}] = $index;
66            }
67            Impl::concat_swizzle($first, $second)
68        }
69    }
70}
71
72/// Creates a vector from the elements of another vector.
73pub trait Swizzle<const N: usize> {
74    /// Map from the elements of the input vector to the output vector.
75    const INDEX: [usize; N];
76
77    /// Creates a new vector from the elements of `vector`.
78    ///
79    /// Lane `i` of the output is `vector[Self::INDEX[i]]`.
80    #[inline]
81    #[must_use = "method returns a new vector and does not mutate the original inputs"]
82    fn swizzle<T, const M: usize>(vector: Simd<T, M>) -> Simd<T, N>
83    where
84        T: SimdElement,
85    {
86        // Safety: `vector` is a vector, and the index is a const vector of u32.
87        unsafe {
88            core::intrinsics::simd::simd_shuffle(
89                vector,
90                vector,
91                const {
92                    let mut output = [0; N];
93                    let mut i = 0;
94                    while i < N {
95                        let index = Self::INDEX[i];
96                        assert!(index as u32 as usize == index);
97                        assert!(
98                            index < M,
99                            "source element index exceeds input vector length"
100                        );
101                        output[i] = index as u32;
102                        i += 1;
103                    }
104
105                    // The index list needs to be returned as a vector.
106                    #[repr(simd)]
107                    struct SimdShuffleIdx<const LEN: usize>([u32; LEN]);
108                    SimdShuffleIdx(output)
109                },
110            )
111        }
112    }
113
114    /// Creates a new vector from the elements of `first` and `second`.
115    ///
116    /// Lane `i` of the output is `concat[Self::INDEX[i]]`, where `concat` is the concatenation of
117    /// `first` and `second`.
118    #[inline]
119    #[must_use = "method returns a new vector and does not mutate the original inputs"]
120    fn concat_swizzle<T, const M: usize>(first: Simd<T, M>, second: Simd<T, M>) -> Simd<T, N>
121    where
122        T: SimdElement,
123    {
124        // Safety: `first` and `second` are vectors, and the index is a const vector of u32.
125        unsafe {
126            core::intrinsics::simd::simd_shuffle(
127                first,
128                second,
129                const {
130                    let mut output = [0; N];
131                    let mut i = 0;
132                    while i < N {
133                        let index = Self::INDEX[i];
134                        assert!(index as u32 as usize == index);
135                        assert!(
136                            index < 2 * M,
137                            "source element index exceeds input vector length"
138                        );
139                        output[i] = index as u32;
140                        i += 1;
141                    }
142
143                    // The index list needs to be returned as a vector.
144                    #[repr(simd)]
145                    struct SimdShuffleIdx<const LEN: usize>([u32; LEN]);
146                    SimdShuffleIdx(output)
147                },
148            )
149        }
150    }
151
152    /// Creates a new mask from the elements of `mask`.
153    ///
154    /// Element `i` of the output is `mask[Self::INDEX[i]]`.
155    #[inline]
156    #[must_use = "method returns a new mask and does not mutate the original inputs"]
157    fn swizzle_mask<T, const M: usize>(mask: Mask<T, M>) -> Mask<T, N>
158    where
159        T: MaskElement,
160    {
161        // SAFETY: all elements of this mask come from another mask
162        unsafe { Mask::from_simd_unchecked(Self::swizzle(mask.to_simd())) }
163    }
164
165    /// Creates a new mask from the elements of `first` and `second`.
166    ///
167    /// Element `i` of the output is `concat[Self::INDEX[i]]`, where `concat` is the concatenation of
168    /// `first` and `second`.
169    #[inline]
170    #[must_use = "method returns a new mask and does not mutate the original inputs"]
171    fn concat_swizzle_mask<T, const M: usize>(first: Mask<T, M>, second: Mask<T, M>) -> Mask<T, N>
172    where
173        T: MaskElement,
174    {
175        // SAFETY: all elements of this mask come from another mask
176        unsafe {
177            Mask::from_simd_unchecked(Self::concat_swizzle(first.to_simd(), second.to_simd()))
178        }
179    }
180}
181
182impl<T, const N: usize> Simd<T, N>
183where
184    T: SimdElement,
185{
186    /// Reverse the order of the elements in the vector.
187    #[inline]
188    #[must_use = "method returns a new vector and does not mutate the original inputs"]
189    pub fn reverse(self) -> Self {
190        struct Reverse;
191
192        impl<const N: usize> Swizzle<N> for Reverse {
193            const INDEX: [usize; N] = const {
194                let mut index = [0; N];
195                let mut i = 0;
196                while i < N {
197                    index[i] = N - i - 1;
198                    i += 1;
199                }
200                index
201            };
202        }
203
204        Reverse::swizzle(self)
205    }
206
207    /// Rotates the vector such that the first `OFFSET` elements of the slice move to the end
208    /// while the last `self.len() - OFFSET` elements move to the front. After calling `rotate_elements_left`,
209    /// the element previously at index `OFFSET` will become the first element in the slice.
210    /// ```
211    /// # #![feature(portable_simd)]
212    /// # #[cfg(feature = "as_crate")] use core_simd::simd::Simd;
213    /// # #[cfg(not(feature = "as_crate"))] use core::simd::Simd;
214    /// let a = Simd::from_array([0, 1, 2, 3]);
215    /// let x = a.rotate_elements_left::<3>();
216    /// assert_eq!(x.to_array(), [3, 0, 1, 2]);
217    ///
218    /// let y = a.rotate_elements_left::<7>();
219    /// assert_eq!(y.to_array(), [3, 0, 1, 2]);
220    /// ```
221    #[inline]
222    #[must_use = "method returns a new vector and does not mutate the original inputs"]
223    pub fn rotate_elements_left<const OFFSET: usize>(self) -> Self {
224        struct Rotate<const OFFSET: usize>;
225
226        impl<const OFFSET: usize, const N: usize> Swizzle<N> for Rotate<OFFSET> {
227            const INDEX: [usize; N] = const {
228                let offset = OFFSET % N;
229                let mut index = [0; N];
230                let mut i = 0;
231                while i < N {
232                    index[i] = (i + offset) % N;
233                    i += 1;
234                }
235                index
236            };
237        }
238
239        Rotate::<OFFSET>::swizzle(self)
240    }
241
242    /// Rotates the vector such that the first `self.len() - OFFSET` elements of the vector move to
243    /// the end while the last `OFFSET` elements move to the front. After calling `rotate_elements_right`,
244    /// the element previously at index `self.len() - OFFSET` will become the first element in the slice.
245    /// ```
246    /// # #![feature(portable_simd)]
247    /// # #[cfg(feature = "as_crate")] use core_simd::simd::Simd;
248    /// # #[cfg(not(feature = "as_crate"))] use core::simd::Simd;
249    /// let a = Simd::from_array([0, 1, 2, 3]);
250    /// let x = a.rotate_elements_right::<3>();
251    /// assert_eq!(x.to_array(), [1, 2, 3, 0]);
252    ///
253    /// let y = a.rotate_elements_right::<7>();
254    /// assert_eq!(y.to_array(), [1, 2, 3, 0]);
255    /// ```
256    #[inline]
257    #[must_use = "method returns a new vector and does not mutate the original inputs"]
258    pub fn rotate_elements_right<const OFFSET: usize>(self) -> Self {
259        struct Rotate<const OFFSET: usize>;
260
261        impl<const OFFSET: usize, const N: usize> Swizzle<N> for Rotate<OFFSET> {
262            const INDEX: [usize; N] = const {
263                let offset = N - OFFSET % N;
264                let mut index = [0; N];
265                let mut i = 0;
266                while i < N {
267                    index[i] = (i + offset) % N;
268                    i += 1;
269                }
270                index
271            };
272        }
273
274        Rotate::<OFFSET>::swizzle(self)
275    }
276
277    /// Shifts the vector elements to the left by `OFFSET`, filling in with
278    /// `padding` from the right.
279    /// ```
280    /// # #![feature(portable_simd)]
281    /// # #[cfg(feature = "as_crate")] use core_simd::simd::Simd;
282    /// # #[cfg(not(feature = "as_crate"))] use core::simd::Simd;
283    /// let a = Simd::from_array([0, 1, 2, 3]);
284    /// let x = a.shift_elements_left::<3>(255);
285    /// assert_eq!(x.to_array(), [3, 255, 255, 255]);
286    ///
287    /// let y = a.shift_elements_left::<7>(255);
288    /// assert_eq!(y.to_array(), [255, 255, 255, 255]);
289    /// ```
290    #[inline]
291    #[must_use = "method returns a new vector and does not mutate the original inputs"]
292    pub fn shift_elements_left<const OFFSET: usize>(self, padding: T) -> Self {
293        struct Shift<const OFFSET: usize>;
294
295        impl<const OFFSET: usize, const N: usize> Swizzle<N> for Shift<OFFSET> {
296            const INDEX: [usize; N] = const {
297                let mut index = [N; N];
298                let mut i = 0;
299                while i + OFFSET < N {
300                    index[i] = i + OFFSET;
301                    i += 1;
302                }
303                index
304            };
305        }
306
307        Shift::<OFFSET>::concat_swizzle(self, Simd::splat(padding))
308    }
309
310    /// Shifts the vector elements to the right by `OFFSET`, filling in with
311    /// `padding` from the left.
312    /// ```
313    /// # #![feature(portable_simd)]
314    /// # #[cfg(feature = "as_crate")] use core_simd::simd::Simd;
315    /// # #[cfg(not(feature = "as_crate"))] use core::simd::Simd;
316    /// let a = Simd::from_array([0, 1, 2, 3]);
317    /// let x = a.shift_elements_right::<3>(255);
318    /// assert_eq!(x.to_array(), [255, 255, 255, 0]);
319    ///
320    /// let y = a.shift_elements_right::<7>(255);
321    /// assert_eq!(y.to_array(), [255, 255, 255, 255]);
322    /// ```
323    #[inline]
324    #[must_use = "method returns a new vector and does not mutate the original inputs"]
325    pub fn shift_elements_right<const OFFSET: usize>(self, padding: T) -> Self {
326        struct Shift<const OFFSET: usize>;
327
328        impl<const OFFSET: usize, const N: usize> Swizzle<N> for Shift<OFFSET> {
329            const INDEX: [usize; N] = const {
330                let mut index = [N; N];
331                let mut i = OFFSET;
332                while i < N {
333                    index[i] = i - OFFSET;
334                    i += 1;
335                }
336                index
337            };
338        }
339
340        Shift::<OFFSET>::concat_swizzle(self, Simd::splat(padding))
341    }
342
343    /// Interleave two vectors.
344    ///
345    /// The resulting vectors contain elements taken alternatively from `self` and `other`, first
346    /// filling the first result, and then the second.
347    ///
348    /// The reverse of this operation is [`Simd::deinterleave`].
349    ///
350    /// ```
351    /// # #![feature(portable_simd)]
352    /// # use core::simd::Simd;
353    /// let a = Simd::from_array([0, 1, 2, 3]);
354    /// let b = Simd::from_array([4, 5, 6, 7]);
355    /// let (x, y) = a.interleave(b);
356    /// assert_eq!(x.to_array(), [0, 4, 1, 5]);
357    /// assert_eq!(y.to_array(), [2, 6, 3, 7]);
358    /// ```
359    #[inline]
360    #[must_use = "method returns a new vector and does not mutate the original inputs"]
361    pub fn interleave(self, other: Self) -> (Self, Self) {
362        const fn interleave<const N: usize>(high: bool) -> [usize; N] {
363            let mut idx = [0; N];
364            let mut i = 0;
365            while i < N {
366                let dst_index = if high { i + N } else { i };
367                let src_index = dst_index / 2 + (dst_index % 2) * N;
368                idx[i] = src_index;
369                i += 1;
370            }
371            idx
372        }
373
374        struct Lo;
375        struct Hi;
376
377        impl<const N: usize> Swizzle<N> for Lo {
378            const INDEX: [usize; N] = interleave::<N>(false);
379        }
380
381        impl<const N: usize> Swizzle<N> for Hi {
382            const INDEX: [usize; N] = interleave::<N>(true);
383        }
384
385        (
386            Lo::concat_swizzle(self, other),
387            Hi::concat_swizzle(self, other),
388        )
389    }
390
391    /// Deinterleave two vectors.
392    ///
393    /// The first result takes every other element of `self` and then `other`, starting with
394    /// the first element.
395    ///
396    /// The second result takes every other element of `self` and then `other`, starting with
397    /// the second element.
398    ///
399    /// The reverse of this operation is [`Simd::interleave`].
400    ///
401    /// ```
402    /// # #![feature(portable_simd)]
403    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
404    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
405    /// # use simd::Simd;
406    /// let a = Simd::from_array([0, 4, 1, 5]);
407    /// let b = Simd::from_array([2, 6, 3, 7]);
408    /// let (x, y) = a.deinterleave(b);
409    /// assert_eq!(x.to_array(), [0, 1, 2, 3]);
410    /// assert_eq!(y.to_array(), [4, 5, 6, 7]);
411    /// ```
412    #[inline]
413    #[must_use = "method returns a new vector and does not mutate the original inputs"]
414    pub fn deinterleave(self, other: Self) -> (Self, Self) {
415        const fn deinterleave<const N: usize>(second: bool) -> [usize; N] {
416            let mut idx = [0; N];
417            let mut i = 0;
418            while i < N {
419                idx[i] = i * 2 + second as usize;
420                i += 1;
421            }
422            idx
423        }
424
425        struct Even;
426        struct Odd;
427
428        impl<const N: usize> Swizzle<N> for Even {
429            const INDEX: [usize; N] = deinterleave::<N>(false);
430        }
431
432        impl<const N: usize> Swizzle<N> for Odd {
433            const INDEX: [usize; N] = deinterleave::<N>(true);
434        }
435
436        (
437            Even::concat_swizzle(self, other),
438            Odd::concat_swizzle(self, other),
439        )
440    }
441
442    /// Resize a vector.
443    ///
444    /// If `M` > `N`, extends the length of a vector, setting the new elements to `value`.
445    /// If `M` < `N`, truncates the vector to the first `M` elements.
446    ///
447    /// ```
448    /// # #![feature(portable_simd)]
449    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
450    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
451    /// # use simd::u32x4;
452    /// let x = u32x4::from_array([0, 1, 2, 3]);
453    /// assert_eq!(x.resize::<8>(9).to_array(), [0, 1, 2, 3, 9, 9, 9, 9]);
454    /// assert_eq!(x.resize::<2>(9).to_array(), [0, 1]);
455    /// ```
456    #[inline]
457    #[must_use = "method returns a new vector and does not mutate the original inputs"]
458    pub fn resize<const M: usize>(self, value: T) -> Simd<T, M> {
459        struct Resize<const N: usize>;
460        impl<const N: usize, const M: usize> Swizzle<M> for Resize<N> {
461            const INDEX: [usize; M] = const {
462                let mut index = [0; M];
463                let mut i = 0;
464                while i < M {
465                    index[i] = if i < N { i } else { N };
466                    i += 1;
467                }
468                index
469            };
470        }
471        Resize::<N>::concat_swizzle(self, Simd::splat(value))
472    }
473
474    /// Extract a vector from another vector.
475    ///
476    /// ```
477    /// # #![feature(portable_simd)]
478    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
479    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
480    /// # use simd::u32x4;
481    /// let x = u32x4::from_array([0, 1, 2, 3]);
482    /// assert_eq!(x.extract::<1, 2>().to_array(), [1, 2]);
483    /// ```
484    #[inline]
485    #[must_use = "method returns a new vector and does not mutate the original inputs"]
486    pub fn extract<const START: usize, const LEN: usize>(self) -> Simd<T, LEN> {
487        struct Extract<const N: usize, const START: usize>;
488        impl<const N: usize, const START: usize, const LEN: usize> Swizzle<LEN> for Extract<N, START> {
489            const INDEX: [usize; LEN] = const {
490                assert!(START + LEN <= N, "index out of bounds");
491                let mut index = [0; LEN];
492                let mut i = 0;
493                while i < LEN {
494                    index[i] = START + i;
495                    i += 1;
496                }
497                index
498            };
499        }
500        Extract::<N, START>::swizzle(self)
501    }
502}
503
504impl<T, const N: usize> Mask<T, N>
505where
506    T: MaskElement,
507{
508    /// Reverse the order of the elements in the mask.
509    #[inline]
510    #[must_use = "method returns a new vector and does not mutate the original inputs"]
511    pub fn reverse(self) -> Self {
512        // Safety: swizzles are safe for masks
513        unsafe { Self::from_simd_unchecked(self.to_simd().reverse()) }
514    }
515
516    /// Rotates the mask such that the first `OFFSET` elements of the slice move to the end
517    /// while the last `self.len() - OFFSET` elements move to the front. After calling `rotate_elements_left`,
518    /// the element previously at index `OFFSET` will become the first element in the slice.
519    #[inline]
520    #[must_use = "method returns a new vector and does not mutate the original inputs"]
521    pub fn rotate_elements_left<const OFFSET: usize>(self) -> Self {
522        // Safety: swizzles are safe for masks
523        unsafe { Self::from_simd_unchecked(self.to_simd().rotate_elements_left::<OFFSET>()) }
524    }
525
526    /// Rotates the mask such that the first `self.len() - OFFSET` elements of the mask move to
527    /// the end while the last `OFFSET` elements move to the front. After calling `rotate_elements_right`,
528    /// the element previously at index `self.len() - OFFSET` will become the first element in the slice.
529    #[inline]
530    #[must_use = "method returns a new vector and does not mutate the original inputs"]
531    pub fn rotate_elements_right<const OFFSET: usize>(self) -> Self {
532        // Safety: swizzles are safe for masks
533        unsafe { Self::from_simd_unchecked(self.to_simd().rotate_elements_right::<OFFSET>()) }
534    }
535
536    /// Shifts the mask elements to the left by `OFFSET`, filling in with
537    /// `padding` from the right.
538    #[inline]
539    #[must_use = "method returns a new mask and does not mutate the original inputs"]
540    pub fn shift_elements_left<const OFFSET: usize>(self, padding: bool) -> Self {
541        // Safety: swizzles are safe for masks
542        unsafe {
543            Self::from_simd_unchecked(self.to_simd().shift_elements_left::<OFFSET>(if padding {
544                T::TRUE
545            } else {
546                T::FALSE
547            }))
548        }
549    }
550
551    /// Shifts the mask elements to the right by `OFFSET`, filling in with
552    /// `padding` from the left.
553    #[inline]
554    #[must_use = "method returns a new mask and does not mutate the original inputs"]
555    pub fn shift_elements_right<const OFFSET: usize>(self, padding: bool) -> Self {
556        // Safety: swizzles are safe for masks
557        unsafe {
558            Self::from_simd_unchecked(self.to_simd().shift_elements_right::<OFFSET>(if padding {
559                T::TRUE
560            } else {
561                T::FALSE
562            }))
563        }
564    }
565
566    /// Interleave two masks.
567    ///
568    /// The resulting masks contain elements taken alternatively from `self` and `other`, first
569    /// filling the first result, and then the second.
570    ///
571    /// The reverse of this operation is [`Mask::deinterleave`].
572    ///
573    /// ```
574    /// # #![feature(portable_simd)]
575    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
576    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
577    /// # use simd::mask32x4;
578    /// let a = mask32x4::from_array([false, true, false, true]);
579    /// let b = mask32x4::from_array([false, false, true, true]);
580    /// let (x, y) = a.interleave(b);
581    /// assert_eq!(x.to_array(), [false, false, true, false]);
582    /// assert_eq!(y.to_array(), [false, true, true, true]);
583    /// ```
584    #[inline]
585    #[must_use = "method returns a new vector and does not mutate the original inputs"]
586    pub fn interleave(self, other: Self) -> (Self, Self) {
587        let (lo, hi) = self.to_simd().interleave(other.to_simd());
588        // Safety: swizzles are safe for masks
589        unsafe { (Self::from_simd_unchecked(lo), Self::from_simd_unchecked(hi)) }
590    }
591
592    /// Deinterleave two masks.
593    ///
594    /// The first result takes every other element of `self` and then `other`, starting with
595    /// the first element.
596    ///
597    /// The second result takes every other element of `self` and then `other`, starting with
598    /// the second element.
599    ///
600    /// The reverse of this operation is [`Mask::interleave`].
601    ///
602    /// ```
603    /// # #![feature(portable_simd)]
604    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
605    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
606    /// # use simd::mask32x4;
607    /// let a = mask32x4::from_array([false, true, false, true]);
608    /// let b = mask32x4::from_array([false, false, true, true]);
609    /// let (x, y) = a.deinterleave(b);
610    /// assert_eq!(x.to_array(), [false, false, false, true]);
611    /// assert_eq!(y.to_array(), [true, true, false, true]);
612    /// ```
613    #[inline]
614    #[must_use = "method returns a new vector and does not mutate the original inputs"]
615    pub fn deinterleave(self, other: Self) -> (Self, Self) {
616        let (even, odd) = self.to_simd().deinterleave(other.to_simd());
617        // Safety: swizzles are safe for masks
618        unsafe {
619            (
620                Self::from_simd_unchecked(even),
621                Self::from_simd_unchecked(odd),
622            )
623        }
624    }
625
626    /// Resize a mask.
627    ///
628    /// If `M` > `N`, extends the length of a mask, setting the new elements to `value`.
629    /// If `M` < `N`, truncates the mask to the first `M` elements.
630    ///
631    /// ```
632    /// # #![feature(portable_simd)]
633    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
634    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
635    /// # use simd::mask32x4;
636    /// let x = mask32x4::from_array([false, true, true, false]);
637    /// assert_eq!(x.resize::<8>(true).to_array(), [false, true, true, false, true, true, true, true]);
638    /// assert_eq!(x.resize::<2>(true).to_array(), [false, true]);
639    /// ```
640    #[inline]
641    #[must_use = "method returns a new vector and does not mutate the original inputs"]
642    pub fn resize<const M: usize>(self, value: bool) -> Mask<T, M> {
643        // Safety: swizzles are safe for masks
644        unsafe {
645            Mask::<T, M>::from_simd_unchecked(self.to_simd().resize::<M>(if value {
646                T::TRUE
647            } else {
648                T::FALSE
649            }))
650        }
651    }
652
653    /// Extract a vector from another vector.
654    ///
655    /// ```
656    /// # #![feature(portable_simd)]
657    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
658    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
659    /// # use simd::mask32x4;
660    /// let x = mask32x4::from_array([false, true, true, false]);
661    /// assert_eq!(x.extract::<1, 2>().to_array(), [true, true]);
662    /// ```
663    #[inline]
664    #[must_use = "method returns a new vector and does not mutate the original inputs"]
665    pub fn extract<const START: usize, const LEN: usize>(self) -> Mask<T, LEN> {
666        // Safety: swizzles are safe for masks
667        unsafe { Mask::<T, LEN>::from_simd_unchecked(self.to_simd().extract::<START, LEN>()) }
668    }
669}