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}