binius_field/underlier/
underlier_type.rs

1// Copyright 2024-2025 Irreducible Inc.
2
3use std::fmt::Debug;
4
5use bytemuck::{NoUninit, Zeroable};
6use rand::{
7	Rng, RngCore,
8	distributions::{Distribution, Standard},
9};
10use subtle::ConstantTimeEq;
11
12/// Primitive integer underlying a binary field or packed binary field implementation.
13/// Note that this type is not guaranteed to be POD, U1, U2 and U4 have some unused bits.
14pub trait UnderlierType:
15	Debug
16	+ Default
17	+ PartialEq
18	+ Eq
19	+ PartialOrd
20	+ Ord
21	+ ConstantTimeEq
22	+ Copy
23	+ Random
24	+ NoUninit
25	+ Zeroable
26	+ Sized
27	+ Send
28	+ Sync
29	+ 'static
30{
31	/// Number of bits in value
32	const LOG_BITS: usize;
33	/// Number of bits used to represent a value.
34	/// This may not be equal to the number of bits in a type instance.
35	const BITS: usize = 1 << Self::LOG_BITS;
36}
37
38/// A type that is transparently backed by an underlier.
39///
40/// This trait is needed to make it possible getting the underlier type from already defined type.
41/// Bidirectional `From` trait implementations are not enough, because they do not allow getting
42/// underlier type in a generic code.
43///
44/// # Safety
45/// `WithUnderlier` can be implemented for a type only if it's representation is a transparent
46/// `Underlier`'s representation. That's allows us casting references of type and it's underlier in
47/// both directions.
48pub unsafe trait WithUnderlier: Sized + Zeroable + Copy + Send + Sync + 'static {
49	/// Underlier primitive type
50	type Underlier: UnderlierType;
51
52	/// Convert value to underlier.
53	fn to_underlier(self) -> Self::Underlier;
54
55	fn to_underlier_ref(&self) -> &Self::Underlier;
56
57	fn to_underlier_ref_mut(&mut self) -> &mut Self::Underlier;
58
59	fn to_underliers_ref(val: &[Self]) -> &[Self::Underlier];
60
61	fn to_underliers_ref_mut(val: &mut [Self]) -> &mut [Self::Underlier];
62
63	fn to_underliers_arr<const N: usize>(val: [Self; N]) -> [Self::Underlier; N] {
64		val.map(Self::to_underlier)
65	}
66
67	fn to_underliers_arr_ref<const N: usize>(val: &[Self; N]) -> &[Self::Underlier; N] {
68		Self::to_underliers_ref(val)
69			.try_into()
70			.expect("array size is valid")
71	}
72
73	fn to_underliers_arr_ref_mut<const N: usize>(val: &mut [Self; N]) -> &mut [Self::Underlier; N] {
74		Self::to_underliers_ref_mut(val)
75			.try_into()
76			.expect("array size is valid")
77	}
78
79	fn from_underlier(val: Self::Underlier) -> Self;
80
81	fn from_underlier_ref(val: &Self::Underlier) -> &Self;
82
83	fn from_underlier_ref_mut(val: &mut Self::Underlier) -> &mut Self;
84
85	fn from_underliers_ref(val: &[Self::Underlier]) -> &[Self];
86
87	fn from_underliers_ref_mut(val: &mut [Self::Underlier]) -> &mut [Self];
88
89	fn from_underliers_arr<const N: usize>(val: [Self::Underlier; N]) -> [Self; N] {
90		val.map(Self::from_underlier)
91	}
92
93	fn from_underliers_arr_ref<const N: usize>(val: &[Self::Underlier; N]) -> &[Self; N] {
94		Self::from_underliers_ref(val)
95			.try_into()
96			.expect("array size is valid")
97	}
98
99	fn from_underliers_arr_ref_mut<const N: usize>(
100		val: &mut [Self::Underlier; N],
101	) -> &mut [Self; N] {
102		Self::from_underliers_ref_mut(val)
103			.try_into()
104			.expect("array size is valid")
105	}
106
107	#[inline]
108	fn mutate_underlier(self, f: impl FnOnce(Self::Underlier) -> Self::Underlier) -> Self {
109		Self::from_underlier(f(self.to_underlier()))
110	}
111}
112
113unsafe impl<U: UnderlierType> WithUnderlier for U {
114	type Underlier = U;
115
116	#[inline]
117	fn to_underlier(self) -> Self::Underlier {
118		self
119	}
120
121	#[inline]
122	fn to_underlier_ref(&self) -> &Self::Underlier {
123		self
124	}
125
126	#[inline]
127	fn to_underlier_ref_mut(&mut self) -> &mut Self::Underlier {
128		self
129	}
130
131	#[inline]
132	fn to_underliers_ref(val: &[Self]) -> &[Self::Underlier] {
133		val
134	}
135
136	#[inline]
137	fn to_underliers_ref_mut(val: &mut [Self]) -> &mut [Self::Underlier] {
138		val
139	}
140
141	#[inline]
142	fn from_underlier(val: Self::Underlier) -> Self {
143		val
144	}
145
146	#[inline]
147	fn from_underlier_ref(val: &Self::Underlier) -> &Self {
148		val
149	}
150
151	#[inline]
152	fn from_underlier_ref_mut(val: &mut Self::Underlier) -> &mut Self {
153		val
154	}
155
156	#[inline]
157	fn from_underliers_ref(val: &[Self::Underlier]) -> &[Self] {
158		val
159	}
160
161	#[inline]
162	fn from_underliers_ref_mut(val: &mut [Self::Underlier]) -> &mut [Self] {
163		val
164	}
165}
166
167/// A value that can be randomly generated
168pub trait Random {
169	/// Generate random value
170	fn random(rng: impl RngCore) -> Self;
171}
172
173impl<T> Random for T
174where
175	Standard: Distribution<T>,
176{
177	fn random(mut rng: impl RngCore) -> Self {
178		rng.r#gen()
179	}
180}
181
182/// A trait that represents potentially lossy numeric cast.
183/// Is a drop-in replacement of `as _` in a generic code.
184pub trait NumCast<From> {
185	fn num_cast_from(val: From) -> Self;
186}
187
188impl<U: UnderlierType> NumCast<U> for U {
189	#[inline(always)]
190	fn num_cast_from(val: U) -> Self {
191		val
192	}
193}