binius_field/underlier/
underlier_type.rs

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