p3_field/
packed.rs

1use core::ops::{Add, AddAssign, Div, Mul, MulAssign, Sub, SubAssign};
2use core::{mem, slice};
3
4use crate::field::Field;
5use crate::AbstractField;
6
7/// A trait to constrain types that can be packed into a packed value.
8///
9/// The `Packable` trait allows us to specify implementations for potentially conflicting types.
10pub trait Packable: 'static + Default + Copy + Send + Sync + PartialEq + Eq {}
11
12/// # Safety
13/// - `WIDTH` is assumed to be a power of 2.
14/// - If `P` implements `PackedField` then `P` must be castable to/from `[P::Value; P::WIDTH]`
15///   without UB.
16pub unsafe trait PackedValue: 'static + Copy + From<Self::Value> + Send + Sync {
17    type Value: Packable;
18
19    const WIDTH: usize;
20
21    fn from_slice(slice: &[Self::Value]) -> &Self;
22    fn from_slice_mut(slice: &mut [Self::Value]) -> &mut Self;
23
24    /// Similar to `core:array::from_fn`.
25    fn from_fn<F>(f: F) -> Self
26    where
27        F: FnMut(usize) -> Self::Value;
28
29    fn as_slice(&self) -> &[Self::Value];
30    fn as_slice_mut(&mut self) -> &mut [Self::Value];
31
32    fn pack_slice(buf: &[Self::Value]) -> &[Self] {
33        // Sources vary, but this should be true on all platforms we care about.
34        // This should be a const assert, but trait methods can't access `Self` in a const context,
35        // even with inner struct instantiation. So we will trust LLVM to optimize this out.
36        assert!(mem::align_of::<Self>() <= mem::align_of::<Self::Value>());
37        assert!(
38            buf.len() % Self::WIDTH == 0,
39            "Slice length (got {}) must be a multiple of packed field width ({}).",
40            buf.len(),
41            Self::WIDTH
42        );
43        let buf_ptr = buf.as_ptr().cast::<Self>();
44        let n = buf.len() / Self::WIDTH;
45        unsafe { slice::from_raw_parts(buf_ptr, n) }
46    }
47
48    fn pack_slice_with_suffix(buf: &[Self::Value]) -> (&[Self], &[Self::Value]) {
49        let (packed, suffix) = buf.split_at(buf.len() - buf.len() % Self::WIDTH);
50        (Self::pack_slice(packed), suffix)
51    }
52
53    fn pack_slice_mut(buf: &mut [Self::Value]) -> &mut [Self] {
54        assert!(mem::align_of::<Self>() <= mem::align_of::<Self::Value>());
55        assert!(
56            buf.len() % Self::WIDTH == 0,
57            "Slice length (got {}) must be a multiple of packed field width ({}).",
58            buf.len(),
59            Self::WIDTH
60        );
61        let buf_ptr = buf.as_mut_ptr().cast::<Self>();
62        let n = buf.len() / Self::WIDTH;
63        unsafe { slice::from_raw_parts_mut(buf_ptr, n) }
64    }
65
66    fn pack_slice_with_suffix_mut(buf: &mut [Self::Value]) -> (&mut [Self], &mut [Self::Value]) {
67        let (packed, suffix) = buf.split_at_mut(buf.len() - buf.len() % Self::WIDTH);
68        (Self::pack_slice_mut(packed), suffix)
69    }
70
71    fn unpack_slice(buf: &[Self]) -> &[Self::Value] {
72        assert!(mem::align_of::<Self>() >= mem::align_of::<Self::Value>());
73        let buf_ptr = buf.as_ptr().cast::<Self::Value>();
74        let n = buf.len() * Self::WIDTH;
75        unsafe { slice::from_raw_parts(buf_ptr, n) }
76    }
77}
78
79/// # Safety
80/// - See `PackedValue` above.
81pub unsafe trait PackedField: AbstractField<F = Self::Scalar>
82    + PackedValue<Value = Self::Scalar>
83    + From<Self::Scalar>
84    + Add<Self::Scalar, Output = Self>
85    + AddAssign<Self::Scalar>
86    + Sub<Self::Scalar, Output = Self>
87    + SubAssign<Self::Scalar>
88    + Mul<Self::Scalar, Output = Self>
89    + MulAssign<Self::Scalar>
90    // TODO: Implement packed / packed division
91    + Div<Self::Scalar, Output = Self>
92{
93    type Scalar: Field + Add<Self, Output = Self> + Mul<Self, Output = Self> + Sub<Self, Output = Self>;
94
95
96
97    /// Take interpret two vectors as chunks of `block_len` elements. Unpack and interleave those
98    /// chunks. This is best seen with an example. If we have:
99    /// ```text
100    /// A = [x0, y0, x1, y1]
101    /// B = [x2, y2, x3, y3]
102    /// ```
103    ///
104    /// then
105    ///
106    /// ```text
107    /// interleave(A, B, 1) = ([x0, x2, x1, x3], [y0, y2, y1, y3])
108    /// ```
109    ///
110    /// Pairs that were adjacent in the input are at corresponding positions in the output.
111    ///
112    /// `r` lets us set the size of chunks we're interleaving. If we set `block_len = 2`, then for
113    ///
114    /// ```text
115    /// A = [x0, x1, y0, y1]
116    /// B = [x2, x3, y2, y3]
117    /// ```
118    ///
119    /// we obtain
120    ///
121    /// ```text
122    /// interleave(A, B, block_len) = ([x0, x1, x2, x3], [y0, y1, y2, y3])
123    /// ```
124    ///
125    /// We can also think about this as stacking the vectors, dividing them into 2x2 matrices, and
126    /// transposing those matrices.
127    ///
128    /// When `block_len = WIDTH`, this operation is a no-op. `block_len` must divide `WIDTH`. Since
129    /// `WIDTH` is specified to be a power of 2, `block_len` must also be a power of 2. It cannot be
130    /// 0 and it cannot exceed `WIDTH`.
131    fn interleave(&self, other: Self, block_len: usize) -> (Self, Self);
132}
133
134unsafe impl<T: Packable> PackedValue for T {
135    type Value = Self;
136
137    const WIDTH: usize = 1;
138
139    fn from_slice(slice: &[Self::Value]) -> &Self {
140        &slice[0]
141    }
142
143    fn from_slice_mut(slice: &mut [Self::Value]) -> &mut Self {
144        &mut slice[0]
145    }
146
147    fn from_fn<Fn>(mut f: Fn) -> Self
148    where
149        Fn: FnMut(usize) -> Self::Value,
150    {
151        f(0)
152    }
153
154    fn as_slice(&self) -> &[Self::Value] {
155        slice::from_ref(self)
156    }
157
158    fn as_slice_mut(&mut self) -> &mut [Self::Value] {
159        slice::from_mut(self)
160    }
161}
162
163unsafe impl<F: Field> PackedField for F {
164    type Scalar = Self;
165
166    fn interleave(&self, other: Self, block_len: usize) -> (Self, Self) {
167        match block_len {
168            1 => (*self, other),
169            _ => panic!("unsupported block length"),
170        }
171    }
172}
173
174impl Packable for u8 {}
175
176impl Packable for u16 {}
177
178impl Packable for u32 {}
179
180impl Packable for u64 {}
181
182impl Packable for u128 {}