binius_field/underlier/
underlier_type.rs

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