swizzle.rs - source
Description: Source of the Rust file `library/core/src/../../portable-simd/crates/core_simd/src/swizzle.rs`.

#
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}