p3_field/
op_assign_macros.rs

1//! A collection of macros designed to implement simple operations
2//! whose implementations are often boilerplate based off some other operation.
3
4// To help with reading the macros, note that the ? operator indicates an optional argument.
5// If it doesn't appear, all call of ? in the body of the macro disappear.
6//
7// Hence `impl_add_assign!(Mersenne31)` will produce:
8//
9// impl AddAssign for Mersenne31
10// ...
11//
12// whereas `impl_add_assign!(MontyField31, (MontyParameters, MP))` produces:
13//
14// impl<MP: MontyParameters> AddAssign for MontyField31<MP>
15// ...
16
17/// Given a struct which implements `Add` implement `AddAssign<T>` for
18/// any type `T` which implements `Into<Self>`.
19///
20/// `AddAssign` is implemented in a simple way by calling `add`
21/// and assigning the result to `*self`.
22#[macro_export]
23macro_rules! impl_add_assign {
24    ($type:ty $(, ($type_param:ty, $param_name:ty))?) => {
25        paste::paste! {
26            impl<$($param_name: $type_param,)? T: Into<Self>> AddAssign<T> for $type$(<$param_name>)? {
27                #[inline]
28                fn add_assign(&mut self, rhs: T) {
29                    *self = *self + rhs.into();
30                }
31            }
32        }
33    };
34}
35
36/// Given a struct which implements `Add` implement `Sum`.
37///
38/// `Sum` is implemented by just doing a reduce on the iterator.
39#[macro_export]
40macro_rules! ring_sum {
41    ($type:ty $(, ($type_param:ty, $param_name:ty))?) => {
42        paste::paste! {
43            impl$(<$param_name: $type_param>)? Sum for $type$(<$param_name>)? {
44                #[inline]
45                fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
46                    iter.reduce(|x, y| x + y).unwrap_or(Self::ZERO)
47                }
48            }
49        }
50    };
51}
52
53/// Given a struct which implements `Sub` implement `SubAssign<T>` for
54/// any type `T` which implements `Into<Self>`.
55///
56/// `SubAssign` is implemented in a simple way by calling `sub`
57/// and assigning the result to `*self`.
58#[macro_export]
59macro_rules! impl_sub_assign {
60    ($type:ty $(, ($type_param:ty, $param_name:ty))?) => {
61        paste::paste! {
62            impl<$($param_name: $type_param,)? T: Into<Self>> SubAssign<T> for $type$(<$param_name>)? {
63                #[inline]
64                fn sub_assign(&mut self, rhs: T) {
65                    *self = *self - rhs.into();
66                }
67            }
68        }
69    };
70}
71
72/// Given a struct which implements `Mul` implement `MulAssign<T>` for
73/// any type `T` which implements `Into<Self>`.
74///
75/// `MulAssign` is implemented in a simple way by calling `mul`
76/// and assigning the result to `*self`. Similarly `Product` is implemented
77/// in the similarly simple way of just doing a reduce on the iterator.
78#[macro_export]
79macro_rules! impl_mul_methods {
80    ($type:ty $(, ($type_param:ty, $param_name:ty))?) => {
81        paste::paste! {
82            impl<$($param_name: $type_param,)? T: Into<Self>> MulAssign<T> for $type$(<$param_name>)? {
83                #[inline]
84                fn mul_assign(&mut self, rhs: T) {
85                    *self = *self * rhs.into();
86                }
87            }
88
89            impl$(<$param_name: $type_param>)? Product for $type$(<$param_name>)? {
90                #[inline]
91                fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
92                    iter.reduce(|x, y| x * y).unwrap_or(Self::ONE)
93                }
94            }
95        }
96    };
97}
98
99/// Given two structs `Alg` and `Field` where `Alg` implements `From<Field>`, implement
100/// `Add<Field>` for `Alg` and `Add<Alg>` for `Field`.
101///
102/// All are implemented in the simplest way by using `From` to map the `Field` element
103/// to an `Alg` element and then applying the native `add` methods on `Alg` elements.
104#[macro_export]
105macro_rules! impl_add_base_field {
106    ($alg_type:ty, $field_type:ty $(, ($type_param:ty, $param_name:ty))?) => {
107        paste::paste! {
108            impl$(<$param_name: $type_param>)? Add<$field_type$(<$param_name>)?> for $alg_type$(<$param_name>)? {
109                type Output = Self;
110
111                #[inline]
112                fn add(self, rhs: $field_type$(<$param_name>)?) -> Self {
113                    self + Self::from(rhs)
114                }
115            }
116
117            impl$(<$param_name: $type_param>)? Add<$alg_type$(<$param_name>)?> for $field_type$(<$param_name>)? {
118                type Output = $alg_type$(<$param_name>)?;
119
120                #[inline]
121                fn add(self, rhs: $alg_type$(<$param_name>)?) -> Self::Output {
122                    $alg_type::from(self) + rhs
123                }
124            }
125        }
126    };
127}
128
129/// Given two structs `Alg` and `Field` where `Alg` implements `From<Field>`, implement
130/// `Sub<Field>` for `Alg` and `Sub<Alg>` for `Field`.
131///
132/// All are implemented in the simplest way by using `From` to map the `Field` element
133/// to an `Alg` element and then applying the native `sub` methods on `Alg` elements.
134#[macro_export]
135macro_rules! impl_sub_base_field {
136    ($alg_type:ty, $field_type:ty $(, ($type_param:ty, $param_name:ty))?) => {
137        paste::paste! {
138            impl$(<$param_name: $type_param>)? Sub<$field_type$(<$param_name>)?> for $alg_type$(<$param_name>)? {
139                type Output = Self;
140
141                #[inline]
142                fn sub(self, rhs: $field_type$(<$param_name>)?) -> Self {
143                    self - Self::from(rhs)
144                }
145            }
146
147            impl$(<$param_name: $type_param>)? Sub<$alg_type$(<$param_name>)?> for $field_type$(<$param_name>)? {
148                type Output = $alg_type$(<$param_name>)?;
149
150                #[inline]
151                fn sub(self, rhs: $alg_type$(<$param_name>)?) -> Self::Output {
152                    $alg_type::from(self) - rhs
153                }
154            }
155        }
156    };
157}
158
159/// Given two structs `Alg` and `Field` where `Alg` implements `From<Field>`, implement
160/// `Mul<Field>` for `Alg` and `Mul<Alg>` for `Field`.
161///
162/// All are implemented in the simplest way by using `From` to map the `Field` element
163/// to an `Alg` element and then applying the native `mul` methods on `Alg` elements.
164#[macro_export]
165macro_rules! impl_mul_base_field {
166    ($alg_type:ty, $field_type:ty $(, ($type_param:ty, $param_name:ty))?) => {
167        paste::paste! {
168            impl$(<$param_name: $type_param>)? Mul<$field_type$(<$param_name>)?> for $alg_type$(<$param_name>)? {
169                type Output = Self;
170
171                #[inline]
172                fn mul(self, rhs: $field_type$(<$param_name>)?) -> Self {
173                    self * Self::from(rhs)
174                }
175            }
176
177            impl$(<$param_name: $type_param>)? Mul<$alg_type$(<$param_name>)?> for $field_type$(<$param_name>)? {
178                type Output = $alg_type$(<$param_name>)?;
179
180                #[inline]
181                fn mul(self, rhs: $alg_type$(<$param_name>)?) -> Self::Output {
182                    $alg_type::from(self) * rhs
183                }
184            }
185        }
186    };
187}
188
189/// Given two structs `Alg` and `Field` where `Alg` implements `From<Field>`, implement
190/// `Div<Field>` and `DivAssign<Field>` for `Alg`.
191///
192/// Both are implemented in the simplest way by first applying the `.inverse()` map from
193/// `Field` then using the `From` to map the inverse to an `Alg` element before
194///  applying the native `mul` or `mul_assign` methods on `Alg` elements.
195///
196/// This can also be used with `Alg = Field` to implement `Div` and `DivAssign` for Field.
197#[macro_export]
198macro_rules! impl_div_methods {
199    ($alg_type:ty, $field_type:ty $(, ($type_param:ty, $param_name:ty))?) => {
200        paste::paste! {
201            impl$(<$param_name: $type_param>)? Div<$field_type$(<$param_name>)?> for $alg_type$(<$param_name>)? {
202                type Output = Self;
203
204                #[inline]
205                #[allow(clippy::suspicious_arithmetic_impl)]
206                fn div(self, rhs: $field_type$(<$param_name>)?) -> Self {
207                    self * Self::from(rhs.inverse())
208                }
209            }
210
211            impl$(<$param_name: $type_param>)? DivAssign<$field_type$(<$param_name>)?> for $alg_type$(<$param_name>)? {
212                #[inline]
213                #[allow(clippy::suspicious_op_assign_impl)]
214                fn div_assign(&mut self, rhs: $field_type$(<$param_name>)?) {
215                    *self *= Self::from(rhs.inverse());
216                }
217            }
218        }
219    };
220}
221
222/// Given two structs `Alg` and `Field` where `Alg` implements `From<Field>`, implement
223/// `Sum<Field> and Product<Field>` for `Alg`.
224///
225/// Both are implemented in the simplest way by simply computing the Sum/Product as
226/// field elements before mapping to an `Alg` element using `From`.
227#[macro_export]
228macro_rules! impl_sum_prod_base_field {
229    ($alg_type:ty, $field_type:ty $(, ($type_param:ty, $param_name:ty))?) => {
230        paste::paste! {
231            impl$(<$param_name: $type_param>)? Sum<$field_type$(<$param_name>)?> for $alg_type$(<$param_name>)? {
232                #[inline]
233                fn sum<I>(iter: I) -> Self
234                where
235                    I: Iterator<Item = $field_type$(<$param_name>)?>,
236                {
237                    iter.sum::<$field_type$(<$param_name>)?>().into()
238                }
239            }
240
241            impl$(<$param_name: $type_param>)? Product<$field_type$(<$param_name>)?> for $alg_type$(<$param_name>)? {
242                #[inline]
243                fn product<I>(iter: I) -> Self
244                where
245                    I: Iterator<Item = $field_type$(<$param_name>)?>,
246                {
247                    iter.product::<$field_type$(<$param_name>)?>().into()
248                }
249            }
250        }
251    };
252}
253
254/// Given a struct `Alg` which is a wrapper over `[Field; N]` for some `N`,
255/// implement `Distribution<Alg>` for `StandardUniform`.
256///
257/// As `Distribution<Field>` is implemented for `StandardUniform` we can
258/// already generate random `[Field; N]` elements so we just need to wrap the
259/// result in `Alg`'s name.
260#[macro_export]
261macro_rules! impl_rng {
262    ($type:ty $(, ($type_param:ty, $param_name:ty))?) => {
263        paste::paste! {
264            impl$(<$param_name: $type_param>)? Distribution<$type$(<$param_name>)?> for StandardUniform {
265                #[inline]
266            fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $type$(<$param_name>)? {
267                $type(rng.random())
268                }
269            }
270        }
271    };
272}
273
274/// Given `Field` and `Algebra` structs where `Algebra` is simply a wrapper around `[Field; N]`
275/// implement `PackedValue` for `Algebra`.
276///
277/// # Safety
278/// `Algebra` must be `repr(transparent)` and castable from to/from `[Field; N]`. Assuming this
279/// holds, these types have the same alignment and size, so all our reference casts are safe.
280#[macro_export]
281macro_rules! impl_packed_value {
282    ($alg_type:ty, $field_type:ty, $width:expr $(, ($type_param:ty, $param_name:ty))?) => {
283        paste::paste! {
284            unsafe impl$(<$param_name: $type_param>)? PackedValue for $alg_type$(<$param_name>)? {
285                type Value = $field_type$(<$param_name>)?;
286
287                const WIDTH: usize = $width;
288
289                #[inline]
290                fn from_slice(slice: &[Self::Value]) -> &Self {
291                    assert_eq!(slice.len(), Self::WIDTH);
292                    unsafe { &*slice.as_ptr().cast() }
293                }
294
295                #[inline]
296                fn from_slice_mut(slice: &mut [Self::Value]) -> &mut Self {
297                    assert_eq!(slice.len(), Self::WIDTH);
298                    unsafe { &mut *slice.as_mut_ptr().cast() }
299                }
300
301                #[inline]
302                fn as_slice(&self) -> &[Self::Value] {
303                    &self.0
304                }
305
306                #[inline]
307                fn as_slice_mut(&mut self) -> &mut [Self::Value] {
308                    &mut self.0
309                }
310
311                #[inline]
312                fn from_fn<F: FnMut(usize) -> Self::Value>(f: F) -> Self {
313                    Self(core::array::from_fn(f))
314                }
315            }
316        }
317    };
318}
319
320pub use {
321    impl_add_assign, impl_add_base_field, impl_div_methods, impl_mul_base_field, impl_mul_methods,
322    impl_packed_value, impl_rng, impl_sub_assign, impl_sub_base_field, impl_sum_prod_base_field,
323    ring_sum,
324};