p3_field/integers.rs
1//! A collection of traits and macros which convert primitive integer types into field elements.
2
3/// A macro which lets us define the function `from_Int`
4/// where `Int` can be replaced by any integer type.
5///
6/// Running, `from_integer_types!(Int)` adds the following code to a trait:
7///
8/// ```rust,ignore
9/// /// Given an integer `r`, return the sum of `r` copies of `ONE`:
10/// ///
11/// /// `r * Self::ONE = Self::ONE + ... + Self::ONE (r times)`.
12/// ///
13/// /// Note that the output only depends on `r mod p`.
14/// ///
15/// /// This should be avoided in performance critical locations.
16/// fn from_Int(int: Int) -> Self {
17/// Self::from_prime_subfield(Self::PrimeSubfield::from_int(int))
18/// }
19/// ```
20///
21/// This macro can be run for any `Int` where `Self::PrimeSubfield` implements `QuotientMap<Int>`.
22/// It considerably cuts down on the amount of copy/pasted code.
23macro_rules! from_integer_types {
24 ($($type:ty),* $(,)? ) => {
25 $( paste::paste!{
26 /// Given an integer `r`, return the sum of `r` copies of `ONE`:
27 ///
28 /// `r * Self::ONE = Self::ONE + ... + Self::ONE (r times)`.
29 ///
30 /// Note that the output only depends on `r mod p`.
31 ///
32 /// This should be avoided in performance critical locations.
33 fn [<from_ $type>](int: $type) -> Self {
34 Self::from_prime_subfield(Self::PrimeSubfield::from_int(int))
35 }
36 }
37 )*
38 };
39}
40
41pub(crate) use from_integer_types;
42
43/// Implementation of the quotient map `ℤ -> ℤ/p` which sends an integer `r` to its conjugacy class `[r]`.
44///
45/// This is the key trait allowing us to convert integers into field elements. Each prime field
46/// should implement this for all primitive integer types.
47pub trait QuotientMap<Int>: Sized {
48 /// Convert a given integer into an element of the field `ℤ/p`.
49 ///
50 /// This is the most generic method which makes no assumptions on the size of the input.
51 /// Where possible, this method should be used with the smallest possible integer type.
52 /// For example, if a 32-bit integer `x` is known to be less than `2^16`, then
53 /// `from_int(x as u16)` will often be faster than `from_int(x)`.
54 ///
55 /// This method is also strongly preferred over `from_canonical_checked/from_canonical_unchecked`.
56 /// It will usually be identical when `Int` is a small type, e.g. `u8/u16` and is safer for
57 /// larger types.
58 #[must_use]
59 fn from_int(int: Int) -> Self;
60
61 /// Convert a given integer into an element of the field `ℤ/p`. The input is checked to
62 /// ensure it lies within a given range.
63 /// - If `Int` is an unsigned integer type the input must lie in `[0, p - 1]`.
64 /// - If `Int` is a signed integer type the input must lie in `[-(p - 1)/2, (p - 1)/2]`.
65 ///
66 /// Return `None` if the input lies outside this range and `Some(val)` otherwise.
67 #[must_use]
68 fn from_canonical_checked(int: Int) -> Option<Self>;
69
70 /// Convert a given integer into an element of the field `ℤ/p`. The input is guaranteed
71 /// to lie within a specific range depending on `p`. If the input lies outside of this
72 /// range, the output is undefined.
73 ///
74 /// In general `from_canonical_unchecked` will be faster for either `signed` or `unsigned`
75 /// types but the specifics will depend on the field.
76 ///
77 /// # Safety
78 /// - If `Int` is an unsigned integer type then the allowed range will include `[0, p - 1]`.
79 /// - If `Int` is a signed integer type then the allowed range will include `[-(p - 1)/2, (p - 1)/2]`.
80 #[must_use]
81 unsafe fn from_canonical_unchecked(int: Int) -> Self;
82}
83
84/// This allows us to avoid some duplication which arises when working with fields which contain a generic parameter.
85///
86/// See `quotient_map_small_int` to see what this will expand to/how to call it. This is not intended for use outside of
87/// that macro.
88#[macro_export]
89macro_rules! quotient_map_small_internals {
90 ($field:ty, $field_size:ty, $small_int:ty) => {
91 #[doc = concat!("Convert a given `", stringify!($small_int), "` integer into an element of the `", stringify!($field), "` field.
92 \n Due to the integer type, the input value is always canonical.")]
93 #[inline]
94 fn from_int(int: $small_int) -> Self {
95 // Check at compile time.
96 const { assert!(size_of::<$small_int>() < size_of::<$field_size>()); }
97 unsafe {
98 Self::from_canonical_unchecked(int as $field_size)
99 }
100 }
101
102 #[doc = concat!("Convert a given `", stringify!($small_int), "` integer into an element of the `", stringify!($field), "` field.
103 \n Due to the integer type, the input value is always canonical.")]
104 #[inline]
105 fn from_canonical_checked(int: $small_int) -> Option<Self> {
106 // Check at compile time.
107 const { assert!(size_of::<$small_int>() < size_of::<$field_size>()); }
108 Some(unsafe {
109 Self::from_canonical_unchecked(int as $field_size)
110 })
111 }
112
113 #[doc = concat!("Convert a given `", stringify!($small_int), "` integer into an element of the `", stringify!($field), "` field.
114 \n Due to the integer type, the input value is always canonical.")]
115 #[inline]
116 unsafe fn from_canonical_unchecked(int: $small_int) -> Self {
117 // Check at compile time.
118 const { assert!(size_of::<$small_int>() < size_of::<$field_size>()); }
119 unsafe {
120 Self::from_canonical_unchecked(int as $field_size)
121 }
122 }
123 };
124}
125
126/// If the integer type is smaller than the field order all possible inputs are canonical.
127/// In such a case we can easily implement `QuotientMap<SmallInt>` as all three methods will coincide.
128///
129/// The range of acceptable integer types depends on the size of the field:
130/// - For 31 bit fields, `SmallInt = u8, u16, i8, i16`.
131/// - For 64 bit fields, `SmallInt = u8, u16, u32, i8, i16, i32`.
132/// - For large fields (E.g. `Bn254`), `SmallInt` can be anything except for the largest primitive integer type `u128/i128`
133///
134/// This macro accepts 3 inputs.
135/// - The name of the prime field `P`
136/// - The larger integer type `Int` which inputs should be cast to.
137/// - A list of smaller integer types to auto implement `QuotientMap<SmallInt>`.
138///
139/// Then `from_int`, `from_canonical_checked`, `from_canonical_unchecked` are all
140/// implemented by casting the input to an `Int` and using the `from_canonical_unchecked`
141/// method from `QuotientMap<Int>`.
142///
143/// For a concrete example, `quotient_map_small_int!(Mersenne31, u32, [u8])` produces the following code:
144///
145/// ```rust,ignore
146/// impl QuotientMap<u8> for Mersenne31 {
147/// /// Convert a given `u8` integer into an element of the `Mersenne31` field.
148/// ///
149/// /// Due to the integer type, the input value is always canonical.
150/// #[inline]
151/// fn from_int(int: u8) -> Mersenne31 {
152/// // Check at compile time.
153/// const { assert!(size_of::<u8>() < size_of::<u32>()); }
154/// unsafe {
155/// Self::from_canonical_unchecked(int as u32)
156/// }
157/// }
158///
159/// /// Convert a given `u8` integer into an element of the `Mersenne31` field.
160/// ///
161/// /// Due to the integer type, the input value is always canonical.
162/// #[inline]
163/// fn from_canonical_checked(int: u8) -> Option<Mersenne31> {
164/// // Check at compile time.
165/// const { assert!(size_of::<u8>() < size_of::<u32>()); }
166/// Some(unsafe {
167/// Self::from_canonical_unchecked(int as u32)
168/// })
169/// }
170///
171/// /// Convert a given `u8` integer into an element of the `Mersenne31` field.
172/// ///
173/// /// Due to the integer type, the input value is always canonical.
174/// #[inline]
175/// unsafe fn from_canonical_unchecked(int: u8) -> Mersenne31 {
176/// // Check at compile time.
177/// const { assert!(size_of::<u8>() < size_of::<u32>()); }
178/// unsafe {
179/// Self::from_canonical_unchecked(int as u32)
180/// }
181/// }
182/// }
183///```
184///
185/// Fields will often use this method twice. Once for unsigned ints and once for signed ints.
186///
187/// We need two slightly different versions for this macro as MontyField31 uses generic parameters.
188#[macro_export]
189macro_rules! quotient_map_small_int {
190 ($field:ty, $field_size:ty, [$($small_int:ty),*] ) => {
191 $(
192 paste::paste!{
193 impl QuotientMap<$small_int> for $field {
194 $crate::quotient_map_small_internals!($field, $field_size, $small_int);
195 }
196 }
197 )*
198 };
199
200 ($field:ty, $field_size:ty, $field_param:ty, [$($small_int:ty),*] ) => {
201 $(
202 paste::paste!{
203 impl<FP: $field_param> QuotientMap<$small_int> for $field<FP> {
204 $crate::quotient_map_small_internals!($field, $field_size, $small_int);
205 }
206 }
207 )*
208 };
209}
210
211/// If the unsigned integer type is large enough, there is often no method better for `from_int` than
212/// just doing a modular reduction to a smaller type.
213///
214/// This macro accepts 6 inputs.
215/// - The name of the prime field `P`
216/// - The smallest natural integer type large enough to contain the field characteristic.
217/// - The characteristic of the field.
218/// - A string giving the range for which from_canonical_checked produces the correct result.
219/// - A string giving the range for which from_canonical_unchecked produces the correct result.
220/// - A list of large integer types to auto implement `QuotientMap<LargeInt>`.
221///
222/// For a concrete example, `quotient_map_large_uint!(Mersenne31, u32, Mersenne31::ORDER_U32, "`\[0, 2^31 - 2\]`", "`\[0, 2^31 - 1\]`", [u128])` would produce the following code:
223///
224/// ```rust,ignore
225/// impl QuotientMap<u128> for Mersenne31 {
226/// /// Convert a given `u128` integer into an element of the `Mersenne31` field.
227/// ///
228/// /// Uses a modular reduction to reduce to canonical form.
229/// /// This should be avoided in performance critical locations.
230/// #[inline]
231/// fn from_int(int: u128) -> Mersenne31 {
232/// // Check at compile time.
233/// const { assert!(size_of::<u128>() > size_of::<u32>()); }
234/// let red = (int % (Mersenne31::ORDER_U32 as u128)) as u32;
235/// unsafe {
236/// // This is safe as red is less than the field order by assumption.
237/// Self::from_canonical_unchecked(red)
238/// }
239/// }
240///
241/// /// Convert a given `u128` integer into an element of the `Mersenne31` field.
242/// ///
243/// /// Returns `None` if the input does not lie in the range: [0, 2^31 - 2].
244/// #[inline]
245/// fn from_canonical_checked(int: u128) -> Option<Mersenne31> {
246/// if int < Mersenne31::ORDER_U32 as u128 {
247/// unsafe {
248/// // This is safe as we just checked that int is less than the field order.
249/// Some(Self::from_canonical_unchecked(int as u32))
250/// }
251/// } else {
252/// None
253/// }
254/// }
255///
256/// /// Convert a given `u128` integer into an element of the `Mersenne31` field.
257/// ///
258/// /// # Safety
259/// /// The input must lie in the range:", [0, 2^31 - 1].
260/// #[inline]
261/// unsafe fn from_canonical_unchecked(int: u128) -> Mersenne31 {
262/// unsafe {
263/// Self::from_canonical_unchecked(int as u32)
264/// }
265/// }
266/// }
267///```
268#[macro_export]
269macro_rules! quotient_map_large_uint {
270 ($field:ty, $field_size:ty, $field_order:expr, $checked_bounds:literal, $unchecked_bounds:literal, [$($large_int:ty),*] ) => {
271 $(
272 impl QuotientMap<$large_int> for $field {
273 #[doc = concat!("Convert a given `", stringify!($large_int), "` integer into an element of the `", stringify!($field), "` field.
274 \n Uses a modular reduction to reduce to canonical form. \n This should be avoided in performance critical locations.")]
275 #[inline]
276 fn from_int(int: $large_int) -> $field {
277 const { assert!(size_of::<$large_int>() > size_of::<$field_size>()); }
278 let red = (int % ($field_order as $large_int)) as $field_size;
279 unsafe {
280 // This is safe as red is less than the field order by assumption.
281 Self::from_canonical_unchecked(red)
282 }
283 }
284
285 #[doc = concat!("Convert a given `", stringify!($large_int), "` integer into an element of the `", stringify!($field), "` field.
286 \n Returns `None` if the input does not lie in the range:", $checked_bounds, ".")]
287 #[inline]
288 fn from_canonical_checked(int: $large_int) -> Option<$field> {
289 if int < $field_order as $large_int {
290 unsafe {
291 // This is safe as we just checked that int is less than the field order.
292 Some(Self::from_canonical_unchecked(int as $field_size))
293 }
294 } else {
295 None
296 }
297 }
298
299 #[doc = concat!("Convert a given `", stringify!($large_int), "` integer into an element of the `", stringify!($field), "` field.")]
300 ///
301 /// # Safety
302 #[doc = concat!("The input must lie in the range:", $unchecked_bounds, ".")]
303 #[inline]
304 unsafe fn from_canonical_unchecked(int: $large_int) -> $field {
305 unsafe {
306 Self::from_canonical_unchecked(int as $field_size)
307 }
308 }
309 }
310 )*
311 };
312}
313
314/// For large signed integer types, a simple method which is usually good enough is to simply check the sign and use this to
315/// pass to the equivalent unsigned method.
316///
317/// This will often not be the fastest implementation but should be good enough for most cases.
318///
319/// This macro accepts 4 inputs.
320/// - The name of the prime field `P`.
321/// - The smallest natural integer type large enough to contain the field characteristic.
322/// - A string giving the range for which from_canonical_checked produces the correct result.
323/// - A string giving the range for which from_canonical_unchecked produces the correct result.
324/// - A list of pairs of large sign and unsigned integer types to auto implement `QuotientMap<LargeSignInt>`.
325///
326/// For a concrete example, `quotient_map_large_iint!(Mersenne31, i32, "`\[-2^30, 2^30\]`", "`\[1 - 2^31, 2^31 - 1\]`", [(i128, u128)])` would produce the following code:
327///
328/// ```rust,ignore
329/// impl QuotientMap<i128> for Mersenne31 {
330/// /// Convert a given `i128` integer into an element of the `Mersenne31` field.
331/// ///
332/// /// This checks the sign and then makes use of the equivalent method for unsigned integers.
333/// /// This should be avoided in performance critical locations.
334/// #[inline]
335/// fn from_int(int: i128) -> Mersenne31 {
336/// if int >= 0 {
337/// Self::from_int(int as u128)
338/// } else {
339/// -Self::from_int(-int as u128)
340/// }
341/// }
342///
343/// /// Convert a given `i128` integer into an element of the `Mersenne31` field.
344/// ///
345/// /// Returns `None` if the input does not lie in the range: `[-2^30, 2^30]`.
346/// #[inline]
347/// fn from_canonical_checked(int: i128) -> Option<Mersenne31> {
348/// // We just check that int fits into an i32 now and then use the i32 method.
349/// let int_small = TryInto::<i32>::try_into(int);
350/// if int_small.is_ok() {
351/// Self::from_canonical_checked(int_small.unwrap())
352/// } else {
353/// None
354/// }
355/// }
356///
357/// /// Convert a given `i128` integer into an element of the `Mersenne31` field.
358/// ///
359/// /// # Safety
360/// /// The input must lie in the range:", `[1 - 2^31, 2^31 - 1]`.
361/// #[inline]
362/// unsafe fn from_canonical_unchecked(int: i128) -> Mersenne31 {
363/// unsafe {
364/// Self::from_canonical_unchecked(int as i32)
365/// }
366/// }
367/// }
368///```
369#[macro_export]
370macro_rules! quotient_map_large_iint {
371 ($field:ty, $field_size:ty, $checked_bounds:literal, $unchecked_bounds:literal, [$(($large_signed_int:ty, $large_int:ty)),*] ) => {
372 $(
373 impl QuotientMap<$large_signed_int> for $field {
374 #[doc = concat!("Convert a given `", stringify!($large_signed_int), "` integer into an element of the `", stringify!($field), "` field.
375 \n This checks the sign and then makes use of the equivalent method for unsigned integers. \n This should be avoided in performance critical locations.")]
376 #[inline]
377 fn from_int(int: $large_signed_int) -> $field {
378 if int >= 0 {
379 Self::from_int(int as $large_int)
380 } else {
381 -Self::from_int(-int as $large_int)
382 }
383 }
384
385 #[doc = concat!("Convert a given `", stringify!($large_int), "` integer into an element of the `", stringify!($field), "` field.
386 \n Returns `None` if the input does not lie in the range:", $checked_bounds, ".")]
387 #[inline]
388 fn from_canonical_checked(int: $large_signed_int) -> Option<$field> {
389 let int_small = TryInto::<$field_size>::try_into(int).ok();
390
391 // The type of the following is Option<Option<$field>>.
392 // We use the ? operator to convert it to Option<$field>, with
393 // None and Some(None) both becoming None.
394 int_small.map(Self::from_canonical_checked)?
395 }
396
397 #[doc = concat!("Convert a given `", stringify!($large_int), "` integer into an element of the `", stringify!($field), "` field.")]
398 ///
399 /// # Safety
400 #[doc = concat!("The input must lie in the range:", $unchecked_bounds, ".")]
401 #[inline]
402 unsafe fn from_canonical_unchecked(int: $large_signed_int) -> $field {
403 unsafe {
404 Self::from_canonical_unchecked(int as $field_size)
405 }
406 }
407 }
408 )*
409 };
410}
411
412/// We implement `QuotientMap<usize>` (`QuotientMap<isize>`) by matching against the size of `usize` (`isize`)
413/// and then converting `usize` (`isize`) into the equivalent matching integer type.
414///
415/// The code is identical for both `usize` and `isize` outside of replacing some u's by i's so we use a macro
416/// to avoid the copy and paste.
417macro_rules! impl_u_i_size {
418 ($intsize:ty, $int8:ty, $int16:ty, $int32:ty, $int64:ty, $int128:ty) => {
419 impl<
420 F: QuotientMap<$int8>
421 + QuotientMap<$int16>
422 + QuotientMap<$int32>
423 + QuotientMap<$int64>
424 + QuotientMap<$int128>,
425 > QuotientMap<$intsize> for F
426 {
427 #[doc = concat!("We use the `from_int` method of the primitive integer type identical to `", stringify!($intsize), "` on this machine")]
428 fn from_int(int: $intsize) -> Self {
429 match size_of::<$intsize>() {
430 1 => Self::from_int(int as $int8),
431 2 => Self::from_int(int as $int16),
432 4 => Self::from_int(int as $int32),
433 8 => Self::from_int(int as $int64),
434 16 => Self::from_int(int as $int128),
435 _ => unreachable!(concat!(stringify!($intsize), "is not equivalent to any primitive integer types.")),
436 }
437 }
438
439 #[doc = concat!("We use the `from_canonical_checked` method of the primitive integer type identical to `", stringify!($intsize), "` on this machine")]
440 fn from_canonical_checked(int: $intsize) -> Option<Self> {
441 match size_of::<$intsize>() {
442 1 => Self::from_canonical_checked(int as $int8),
443 2 => Self::from_canonical_checked(int as $int16),
444 4 => Self::from_canonical_checked(int as $int32),
445 8 => Self::from_canonical_checked(int as $int64),
446 16 => Self::from_canonical_checked(int as $int128),
447 _ => unreachable!(concat!(stringify!($intsize), " is not equivalent to any primitive integer types.")),
448 }
449 }
450
451 #[doc = concat!("We use the `from_canonical_unchecked` method of the primitive integer type identical to `", stringify!($intsize), "` on this machine")]
452 unsafe fn from_canonical_unchecked(int: $intsize) -> Self {
453 unsafe {
454 match size_of::<$intsize>() {
455 1 => Self::from_canonical_unchecked(int as $int8),
456 2 => Self::from_canonical_unchecked(int as $int16),
457 4 => Self::from_canonical_unchecked(int as $int32),
458 8 => Self::from_canonical_unchecked(int as $int64),
459 16 => Self::from_canonical_unchecked(int as $int128),
460 _ => unreachable!(concat!(stringify!($intsize), " is not equivalent to any primitive integer types.")),
461 }
462 }
463 }
464 }
465 };
466}
467
468impl_u_i_size!(usize, u8, u16, u32, u64, u128);
469impl_u_i_size!(isize, i8, i16, i32, i64, i128);
470
471/// A simple macro which allows us to implement the `RawSerializable` trait for any 32-bit field.
472/// The field must implement PrimeField32.
473///
474/// This macro doesn't need any inputs as the implementation is identical for all 32-bit fields.
475#[macro_export]
476macro_rules! impl_raw_serializable_primefield32 {
477 () => {
478 const NUM_BYTES: usize = 4;
479
480 #[allow(refining_impl_trait)]
481 #[inline]
482 fn into_bytes(self) -> [u8; 4] {
483 self.to_unique_u32().to_le_bytes()
484 }
485
486 #[inline]
487 fn into_u32_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u32> {
488 // As every element is 32 bits, we can just convert the input to a unique u32.
489 input.into_iter().map(|x| x.to_unique_u32())
490 }
491
492 #[inline]
493 fn into_u64_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u64> {
494 let mut input = input.into_iter();
495 iter::from_fn(move || {
496 // If the first input.next() returns None, we return None.
497 let a = input.next()?;
498 // Otherwise we either pack 2 32 bit elements together if the iterator
499 // gives a second value or just cast the 32 bit element to 64 bits.
500 if let Some(b) = input.next() {
501 Some(a.to_unique_u64() | b.to_unique_u64() << 32)
502 } else {
503 Some(a.to_unique_u64())
504 }
505 })
506 }
507
508 #[inline]
509 fn into_parallel_byte_streams<const N: usize>(
510 input: impl IntoIterator<Item = [Self; N]>,
511 ) -> impl IntoIterator<Item = [u8; N]> {
512 input.into_iter().flat_map(|vector| {
513 let bytes = vector.map(|elem| elem.into_bytes());
514 (0..Self::NUM_BYTES).map(move |i| array::from_fn(|j| bytes[j][i]))
515 })
516 }
517
518 #[inline]
519 fn into_parallel_u32_streams<const N: usize>(
520 input: impl IntoIterator<Item = [Self; N]>,
521 ) -> impl IntoIterator<Item = [u32; N]> {
522 // As every element is 32 bits, we can just convert the input to a unique u32.
523 input.into_iter().map(|vec| vec.map(|x| x.to_unique_u32()))
524 }
525
526 #[inline]
527 fn into_parallel_u64_streams<const N: usize>(
528 input: impl IntoIterator<Item = [Self; N]>,
529 ) -> impl IntoIterator<Item = [u64; N]> {
530 let mut input = input.into_iter();
531 iter::from_fn(move || {
532 // If the first input.next() returns None, we return None.
533 let a = input.next()?;
534 // Otherwise we either pack pairs of 32 bit elements together if the iterator
535 // gives two arrays of or just cast the 32 bit elements to 64 bits.
536 if let Some(b) = input.next() {
537 let ab = array::from_fn(|i| {
538 let ai = a[i].to_unique_u64();
539 let bi = b[i].to_unique_u64();
540 ai | (bi << 32)
541 });
542 Some(ab)
543 } else {
544 Some(a.map(|x| x.to_unique_u64()))
545 }
546 })
547 }
548 };
549}
550
551/// A simple macro which allows us to implement the `RawSerializable` trait for any 64-bit field.
552/// The field must implement PrimeField64 (and should not implement PrimeField32).
553///
554/// This macro doesn't need any inputs as the implementation is identical for all 64-bit fields.
555#[macro_export]
556macro_rules! impl_raw_serializable_primefield64 {
557 () => {
558 const NUM_BYTES: usize = 8;
559
560 #[allow(refining_impl_trait)]
561 #[inline]
562 fn into_bytes(self) -> [u8; 8] {
563 self.to_unique_u64().to_le_bytes()
564 }
565
566 #[inline]
567 fn into_u32_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u32> {
568 input.into_iter().flat_map(|x| {
569 let x_u64 = x.to_unique_u64();
570 [x_u64 as u32, (x_u64 >> 32) as u32]
571 })
572 }
573
574 #[inline]
575 fn into_u64_stream(input: impl IntoIterator<Item = Self>) -> impl IntoIterator<Item = u64> {
576 // As every element is 64 bits, we can just convert the input to a unique u64.
577 input.into_iter().map(|x| x.to_unique_u64())
578 }
579
580 #[inline]
581 fn into_parallel_byte_streams<const N: usize>(
582 input: impl IntoIterator<Item = [Self; N]>,
583 ) -> impl IntoIterator<Item = [u8; N]> {
584 input.into_iter().flat_map(|vector| {
585 let bytes = vector.map(|elem| elem.into_bytes());
586 (0..Self::NUM_BYTES).map(move |i| array::from_fn(|j| bytes[j][i]))
587 })
588 }
589
590 #[inline]
591 fn into_parallel_u32_streams<const N: usize>(
592 input: impl IntoIterator<Item = [Self; N]>,
593 ) -> impl IntoIterator<Item = [u32; N]> {
594 input.into_iter().flat_map(|vec| {
595 let vec_64 = vec.map(|x| x.to_unique_u64());
596 let vec_32_lo = vec_64.map(|x| x as u32);
597 let vec_32_hi = vec_64.map(|x| (x >> 32) as u32);
598 [vec_32_lo, vec_32_hi]
599 })
600 }
601
602 #[inline]
603 fn into_parallel_u64_streams<const N: usize>(
604 input: impl IntoIterator<Item = [Self; N]>,
605 ) -> impl IntoIterator<Item = [u64; N]> {
606 // As every element is 64 bits, we can just convert the input to a unique u64.
607 input.into_iter().map(|vec| vec.map(|x| x.to_unique_u64()))
608 }
609 };
610}