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	distributions::{Distribution, Standard},
8	Rng, RngCore,
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 underlier type
42/// in a generic code.
43///
44/// # Safety
45/// `WithUnderlier` can be implemented for a type only if it's representation is a transparent `Underlier`'s representation.
46/// That's allows us casting references of type and it's underlier in both directions.
47pub unsafe trait WithUnderlier: Sized + Zeroable + Copy + Send + Sync + 'static {
48	/// Underlier primitive type
49	type Underlier: UnderlierType;
50
51	/// Convert value to underlier.
52	fn to_underlier(self) -> Self::Underlier;
53
54	fn to_underlier_ref(&self) -> &Self::Underlier;
55
56	fn to_underlier_ref_mut(&mut self) -> &mut Self::Underlier;
57
58	fn to_underliers_ref(val: &[Self]) -> &[Self::Underlier];
59
60	fn to_underliers_ref_mut(val: &mut [Self]) -> &mut [Self::Underlier];
61
62	fn to_underliers_arr<const N: usize>(val: [Self; N]) -> [Self::Underlier; N] {
63		val.map(Self::to_underlier)
64	}
65
66	fn to_underliers_arr_ref<const N: usize>(val: &[Self; N]) -> &[Self::Underlier; N] {
67		Self::to_underliers_ref(val)
68			.try_into()
69			.expect("array size is valid")
70	}
71
72	fn to_underliers_arr_ref_mut<const N: usize>(val: &mut [Self; N]) -> &mut [Self::Underlier; N] {
73		Self::to_underliers_ref_mut(val)
74			.try_into()
75			.expect("array size is valid")
76	}
77
78	fn from_underlier(val: Self::Underlier) -> Self;
79
80	fn from_underlier_ref(val: &Self::Underlier) -> &Self;
81
82	fn from_underlier_ref_mut(val: &mut Self::Underlier) -> &mut Self;
83
84	fn from_underliers_ref(val: &[Self::Underlier]) -> &[Self];
85
86	fn from_underliers_ref_mut(val: &mut [Self::Underlier]) -> &mut [Self];
87
88	fn from_underliers_arr<const N: usize>(val: [Self::Underlier; N]) -> [Self; N] {
89		val.map(Self::from_underlier)
90	}
91
92	fn from_underliers_arr_ref<const N: usize>(val: &[Self::Underlier; N]) -> &[Self; N] {
93		Self::from_underliers_ref(val)
94			.try_into()
95			.expect("array size is valid")
96	}
97
98	fn from_underliers_arr_ref_mut<const N: usize>(
99		val: &mut [Self::Underlier; N],
100	) -> &mut [Self; N] {
101		Self::from_underliers_ref_mut(val)
102			.try_into()
103			.expect("array size is valid")
104	}
105
106	#[inline]
107	fn mutate_underlier(self, f: impl FnOnce(Self::Underlier) -> Self::Underlier) -> Self {
108		Self::from_underlier(f(self.to_underlier()))
109	}
110}
111
112unsafe impl<U: UnderlierType> WithUnderlier for U {
113	type Underlier = U;
114
115	#[inline]
116	fn to_underlier(self) -> Self::Underlier {
117		self
118	}
119
120	#[inline]
121	fn to_underlier_ref(&self) -> &Self::Underlier {
122		self
123	}
124
125	#[inline]
126	fn to_underlier_ref_mut(&mut self) -> &mut Self::Underlier {
127		self
128	}
129
130	#[inline]
131	fn to_underliers_ref(val: &[Self]) -> &[Self::Underlier] {
132		val
133	}
134
135	#[inline]
136	fn to_underliers_ref_mut(val: &mut [Self]) -> &mut [Self::Underlier] {
137		val
138	}
139
140	#[inline]
141	fn from_underlier(val: Self::Underlier) -> Self {
142		val
143	}
144
145	#[inline]
146	fn from_underlier_ref(val: &Self::Underlier) -> &Self {
147		val
148	}
149
150	#[inline]
151	fn from_underlier_ref_mut(val: &mut Self::Underlier) -> &mut Self {
152		val
153	}
154
155	#[inline]
156	fn from_underliers_ref(val: &[Self::Underlier]) -> &[Self] {
157		val
158	}
159
160	#[inline]
161	fn from_underliers_ref_mut(val: &mut [Self::Underlier]) -> &mut [Self] {
162		val
163	}
164}
165
166/// A value that can be randomly generated
167pub trait Random {
168	/// Generate random value
169	fn random(rng: impl RngCore) -> Self;
170}
171
172impl<T> Random for T
173where
174	Standard: Distribution<T>,
175{
176	fn random(mut rng: impl RngCore) -> Self {
177		rng.gen()
178	}
179}
180
181/// A trait that represents potentially lossy numeric cast.
182/// Is a drop-in replacement of `as _` in a generic code.
183pub trait NumCast<From> {
184	fn num_cast_from(val: From) -> Self;
185}
186
187impl<U: UnderlierType> NumCast<U> for U {
188	#[inline(always)]
189	fn num_cast_from(val: U) -> Self {
190		val
191	}
192}