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