1use crate::{
4 as_packed_field::PackScalar,
5 underlier::{Divisible, WithUnderlier},
6 ExtensionField, Field, PackedField,
7};
8
9pub unsafe trait PackedFieldIndexable: PackedField {
21 fn unpack_scalars(packed: &[Self]) -> &[Self::Scalar];
22 fn unpack_scalars_mut(packed: &mut [Self]) -> &mut [Self::Scalar];
23}
24
25unsafe impl<S, P> PackedFieldIndexable for P
26where
27 S: Field,
28 P: PackedDivisible<S, Scalar = S>,
29{
30 fn unpack_scalars(packed: &[Self]) -> &[Self::Scalar] {
31 P::divide(packed)
32 }
33
34 fn unpack_scalars_mut(packed: &mut [Self]) -> &mut [Self::Scalar] {
35 P::divide_mut(packed)
36 }
37}
38
39#[inline(always)]
43#[allow(clippy::redundant_clone)]
44pub fn is_packed_field_indexable<P: PackedField>() -> bool {
45 struct X<T> {
48 cloned: bool,
49 _pd: std::marker::PhantomData<T>,
50 }
51
52 impl<T> Clone for X<T> {
53 fn clone(&self) -> Self {
54 Self {
55 cloned: true,
56 _pd: std::marker::PhantomData,
57 }
58 }
59 }
60
61 impl<T: PackedFieldIndexable> Copy for X<T> {}
62
63 let arr = [X::<P> {
64 cloned: false,
65 _pd: std::marker::PhantomData,
66 }];
67 let cloned = arr.clone();
68
69 !cloned[0].cloned
70}
71
72#[inline(always)]
73pub fn unpack_if_possible<P: PackedField, R>(
74 slice: &[P],
75 unpacked_fn: impl FnOnce(&[P::Scalar]) -> R,
76 fallback_fn: impl FnOnce(&[P]) -> R,
77) -> R {
78 if is_packed_field_indexable::<P>() {
79 let unpacked = unsafe {
80 std::slice::from_raw_parts(
81 slice.as_ptr() as *const P::Scalar,
82 slice.len() << P::LOG_WIDTH,
83 )
84 };
85 unpacked_fn(unpacked)
86 } else {
87 fallback_fn(slice)
88 }
89}
90
91#[inline(always)]
92pub fn unpack_if_possible_mut<P: PackedField, R>(
93 slice: &mut [P],
94 unpacked_fn: impl FnOnce(&mut [P::Scalar]) -> R,
95 fallback_fn: impl FnOnce(&mut [P]) -> R,
96) -> R {
97 if is_packed_field_indexable::<P>() {
98 let unpacked = unsafe {
99 std::slice::from_raw_parts_mut(
100 slice.as_mut_ptr() as *mut P::Scalar,
101 slice.len() << P::LOG_WIDTH,
102 )
103 };
104 unpacked_fn(unpacked)
105 } else {
106 fallback_fn(slice)
107 }
108}
109
110pub trait PackedExtension<FS: Field>: PackedField<Scalar: ExtensionField<FS>> {
146 type PackedSubfield: PackedField<Scalar = FS>;
147
148 fn cast_bases(packed: &[Self]) -> &[Self::PackedSubfield];
149 fn cast_bases_mut(packed: &mut [Self]) -> &mut [Self::PackedSubfield];
150
151 fn cast_exts(packed: &[Self::PackedSubfield]) -> &[Self];
152 fn cast_exts_mut(packed: &mut [Self::PackedSubfield]) -> &mut [Self];
153
154 fn cast_base(self) -> Self::PackedSubfield;
155 fn cast_base_ref(&self) -> &Self::PackedSubfield;
156 fn cast_base_mut(&mut self) -> &mut Self::PackedSubfield;
157
158 fn cast_ext(base: Self::PackedSubfield) -> Self;
159 fn cast_ext_ref(base: &Self::PackedSubfield) -> &Self;
160 fn cast_ext_mut(base: &mut Self::PackedSubfield) -> &mut Self;
161
162 #[inline(always)]
163 fn cast_base_arr<const N: usize>(packed: [Self; N]) -> [Self::PackedSubfield; N] {
164 packed.map(Self::cast_base)
165 }
166
167 #[inline(always)]
168 fn cast_base_arr_ref<const N: usize>(packed: &[Self; N]) -> &[Self::PackedSubfield; N] {
169 Self::cast_bases(packed)
170 .try_into()
171 .expect("array has size N")
172 }
173
174 #[inline(always)]
175 fn cast_base_arr_mut<const N: usize>(packed: &mut [Self; N]) -> &mut [Self::PackedSubfield; N] {
176 Self::cast_bases_mut(packed)
177 .try_into()
178 .expect("array has size N")
179 }
180
181 #[inline(always)]
182 fn cast_ext_arr<const N: usize>(packed: [Self::PackedSubfield; N]) -> [Self; N] {
183 packed.map(Self::cast_ext)
184 }
185
186 #[inline(always)]
187 fn cast_ext_arr_ref<const N: usize>(packed: &[Self::PackedSubfield; N]) -> &[Self; N] {
188 Self::cast_exts(packed)
189 .try_into()
190 .expect("array has size N")
191 }
192
193 #[inline(always)]
194 fn cast_ext_arr_mut<const N: usize>(packed: &mut [Self::PackedSubfield; N]) -> &mut [Self; N] {
195 Self::cast_exts_mut(packed)
196 .try_into()
197 .expect("array has size N")
198 }
199}
200
201impl<PT, FS> PackedExtension<FS> for PT
202where
203 FS: Field,
204 PT: PackedField<Scalar: ExtensionField<FS>> + WithUnderlier<Underlier: PackScalar<FS>>,
205{
206 type PackedSubfield = <PT::Underlier as PackScalar<FS>>::Packed;
207
208 fn cast_bases(packed: &[Self]) -> &[Self::PackedSubfield] {
209 Self::PackedSubfield::from_underliers_ref(Self::to_underliers_ref(packed))
210 }
211
212 fn cast_bases_mut(packed: &mut [Self]) -> &mut [Self::PackedSubfield] {
213 Self::PackedSubfield::from_underliers_ref_mut(Self::to_underliers_ref_mut(packed))
214 }
215
216 fn cast_exts(base: &[Self::PackedSubfield]) -> &[Self] {
217 Self::from_underliers_ref(Self::PackedSubfield::to_underliers_ref(base))
218 }
219
220 fn cast_exts_mut(base: &mut [Self::PackedSubfield]) -> &mut [Self] {
221 Self::from_underliers_ref_mut(Self::PackedSubfield::to_underliers_ref_mut(base))
222 }
223
224 fn cast_base(self) -> Self::PackedSubfield {
225 Self::PackedSubfield::from_underlier(self.to_underlier())
226 }
227
228 fn cast_base_ref(&self) -> &Self::PackedSubfield {
229 Self::PackedSubfield::from_underlier_ref(self.to_underlier_ref())
230 }
231
232 fn cast_base_mut(&mut self) -> &mut Self::PackedSubfield {
233 Self::PackedSubfield::from_underlier_ref_mut(self.to_underlier_ref_mut())
234 }
235
236 fn cast_ext(base: Self::PackedSubfield) -> Self {
237 Self::from_underlier(base.to_underlier())
238 }
239
240 fn cast_ext_ref(base: &Self::PackedSubfield) -> &Self {
241 Self::from_underlier_ref(base.to_underlier_ref())
242 }
243
244 fn cast_ext_mut(base: &mut Self::PackedSubfield) -> &mut Self {
245 Self::from_underlier_ref_mut(base.to_underlier_ref_mut())
246 }
247}
248
249pub type PackedSubfield<P, F> = <P as PackedExtension<F>>::PackedSubfield;
252
253pub fn recast_packed<P, FSub1, FSub2>(elem: PackedSubfield<P, FSub1>) -> PackedSubfield<P, FSub2>
255where
256 P: PackedField + PackedExtension<FSub1> + PackedExtension<FSub2>,
257 P::Scalar: ExtensionField<FSub1> + ExtensionField<FSub2>,
258 FSub1: Field,
259 FSub2: Field,
260{
261 <P as PackedExtension<FSub2>>::cast_base(<P as PackedExtension<FSub1>>::cast_ext(elem))
262}
263
264pub fn recast_packed_slice<P, FSub1, FSub2>(
266 elems: &[PackedSubfield<P, FSub1>],
267) -> &[PackedSubfield<P, FSub2>]
268where
269 P: PackedField + PackedExtension<FSub1> + PackedExtension<FSub2>,
270 P::Scalar: ExtensionField<FSub1> + ExtensionField<FSub2>,
271 FSub1: Field,
272 FSub2: Field,
273{
274 <P as PackedExtension<FSub2>>::cast_bases(<P as PackedExtension<FSub1>>::cast_exts(elems))
275}
276
277pub fn recast_packed_mut<P, FSub1, FSub2>(
280 elems: &mut [PackedSubfield<P, FSub1>],
281) -> &mut [PackedSubfield<P, FSub2>]
282where
283 P: PackedField + PackedExtension<FSub1> + PackedExtension<FSub2>,
284 P::Scalar: ExtensionField<FSub1> + ExtensionField<FSub2>,
285 FSub1: Field,
286 FSub2: Field,
287{
288 <P as PackedExtension<FSub2>>::cast_bases_mut(<P as PackedExtension<FSub1>>::cast_exts_mut(
289 elems,
290 ))
291}
292
293pub trait RepackedExtension<P: PackedField>:
296 PackedField<Scalar: ExtensionField<P::Scalar>> + PackedExtension<P::Scalar, PackedSubfield = P>
297{
298}
299
300impl<PT1, PT2> RepackedExtension<PT1> for PT2
301where
302 PT1: PackedField,
303 PT2: PackedExtension<PT1::Scalar, PackedSubfield = PT1, Scalar: ExtensionField<PT1::Scalar>>,
304{
305}
306
307pub trait PackedExtensionIndexable<F: Field>:
310 PackedExtension<F, PackedSubfield: PackedFieldIndexable> + PackedField<Scalar: ExtensionField<F>>
311{
312 fn unpack_base_scalars(packed: &[Self]) -> &[F] {
313 Self::PackedSubfield::unpack_scalars(Self::cast_bases(packed))
314 }
315
316 fn unpack_base_scalars_mut(packed: &mut [Self]) -> &mut [F] {
317 Self::PackedSubfield::unpack_scalars_mut(Self::cast_bases_mut(packed))
318 }
319}
320
321impl<F, PT> PackedExtensionIndexable<F> for PT
322where
323 F: Field,
324 PT: PackedExtension<F, PackedSubfield: PackedFieldIndexable>,
325{
326}
327
328pub unsafe trait PackedDivisible<P>: PackedField
339where
340 P: PackedField<Scalar = Self::Scalar>,
341{
342 fn divide(packed: &[Self]) -> &[P];
343 fn divide_mut(packed: &mut [Self]) -> &mut [P];
344}
345
346unsafe impl<PT1, PT2> PackedDivisible<PT2> for PT1
347where
348 PT2: PackedField + WithUnderlier,
349 PT1: PackedField<Scalar = PT2::Scalar> + WithUnderlier<Underlier: Divisible<PT2::Underlier>>,
350{
351 fn divide(packed: &[Self]) -> &[PT2] {
352 let underliers = PT1::to_underliers_ref(packed);
353 let underliers: &[PT2::Underlier] = PT1::Underlier::split_slice(underliers);
354 PT2::from_underliers_ref(underliers)
355 }
356
357 fn divide_mut(packed: &mut [Self]) -> &mut [PT2] {
358 let underliers = PT1::to_underliers_ref_mut(packed);
359 let underliers: &mut [PT2::Underlier] = PT1::Underlier::split_slice_mut(underliers);
360 PT2::from_underliers_ref_mut(underliers)
361 }
362}
363
364#[cfg(test)]
365mod tests {
366 use super::*;
367 use crate::{PackedBinaryField2x8b, PackedBinaryField8x2b};
368
369 #[test]
370 fn test_unpack_if_possible() {
371 let slice = [PackedBinaryField2x8b::zero(); 4];
372
373 let len = unpack_if_possible(&slice, |slice| slice.len(), |slice| slice.len());
374 assert_eq!(len, 8);
375
376 let slice = [PackedBinaryField8x2b::zero(); 4];
377 let len = unpack_if_possible(&slice, |slice| slice.len(), |slice| slice.len());
378 assert_eq!(len, 4);
379 }
380
381 #[test]
382 fn test_unpack_if_possible_mut() {
383 let mut slice = [PackedBinaryField2x8b::zero(); 4];
384
385 let len = unpack_if_possible_mut(&mut slice, |slice| slice.len(), |slice| slice.len());
386 assert_eq!(len, 8);
387
388 let mut slice = [PackedBinaryField8x2b::zero(); 4];
389 let len = unpack_if_possible_mut(&mut slice, |slice| slice.len(), |slice| slice.len());
390 assert_eq!(len, 4);
391 }
392}