core/portable-simd/crates/core_simd/src/
swizzle.rs

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