binius_field/underlier/
underlier_type.rs

1// Copyright 2024-2025 Irreducible Inc.
2
3use std::fmt::Debug;
4
5use bytemuck::{NoUninit, TransparentWrapper, 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:
45	TransparentWrapper<Self::Underlier> + Sized + Zeroable + Copy + Send + Sync + 'static
46{
47	/// Underlier primitive type
48	type Underlier: UnderlierType;
49
50	/// Convert value to underlier.
51	#[inline]
52	fn to_underlier(self) -> Self::Underlier {
53		Self::peel(self)
54	}
55
56	#[inline]
57	fn to_underlier_ref(&self) -> &Self::Underlier {
58		Self::peel_ref(self)
59	}
60
61	#[inline]
62	fn to_underlier_ref_mut(&mut self) -> &mut Self::Underlier {
63		Self::peel_mut(self)
64	}
65
66	#[inline]
67	fn to_underliers_ref(val: &[Self]) -> &[Self::Underlier] {
68		Self::peel_slice(val)
69	}
70
71	#[inline]
72	fn to_underliers_ref_mut(val: &mut [Self]) -> &mut [Self::Underlier] {
73		Self::peel_slice_mut(val)
74	}
75
76	#[inline]
77	fn to_underliers_arr<const N: usize>(val: [Self; N]) -> [Self::Underlier; N] {
78		val.map(Self::to_underlier)
79	}
80
81	#[inline]
82	fn to_underliers_arr_ref<const N: usize>(val: &[Self; N]) -> &[Self::Underlier; N] {
83		Self::to_underliers_ref(val)
84			.try_into()
85			.expect("array size is valid")
86	}
87
88	#[inline]
89	fn to_underliers_arr_ref_mut<const N: usize>(val: &mut [Self; N]) -> &mut [Self::Underlier; N] {
90		Self::to_underliers_ref_mut(val)
91			.try_into()
92			.expect("array size is valid")
93	}
94
95	#[inline]
96	fn from_underlier(val: Self::Underlier) -> Self {
97		Self::wrap(val)
98	}
99
100	#[inline]
101	fn from_underlier_ref(val: &Self::Underlier) -> &Self {
102		Self::wrap_ref(val)
103	}
104
105	#[inline]
106	fn from_underlier_ref_mut(val: &mut Self::Underlier) -> &mut Self {
107		Self::wrap_mut(val)
108	}
109
110	#[inline]
111	fn from_underliers_ref(val: &[Self::Underlier]) -> &[Self] {
112		Self::wrap_slice(val)
113	}
114
115	#[inline]
116	fn from_underliers_ref_mut(val: &mut [Self::Underlier]) -> &mut [Self] {
117		Self::wrap_slice_mut(val)
118	}
119
120	#[inline]
121	fn from_underliers_arr<const N: usize>(val: [Self::Underlier; N]) -> [Self; N] {
122		val.map(Self::from_underlier)
123	}
124
125	#[inline]
126	fn from_underliers_arr_ref<const N: usize>(val: &[Self::Underlier; N]) -> &[Self; N] {
127		Self::from_underliers_ref(val)
128			.try_into()
129			.expect("array size is valid")
130	}
131
132	#[inline]
133	fn from_underliers_arr_ref_mut<const N: usize>(
134		val: &mut [Self::Underlier; N],
135	) -> &mut [Self; N] {
136		Self::from_underliers_ref_mut(val)
137			.try_into()
138			.expect("array size is valid")
139	}
140
141	#[inline]
142	fn mutate_underlier(self, f: impl FnOnce(Self::Underlier) -> Self::Underlier) -> Self {
143		Self::from_underlier(f(self.to_underlier()))
144	}
145}
146
147/// A trait that represents potentially lossy numeric cast.
148/// Is a drop-in replacement of `as _` in a generic code.
149pub trait NumCast<From> {
150	fn num_cast_from(val: From) -> Self;
151}
152
153impl<U: UnderlierType> NumCast<U> for U {
154	#[inline(always)]
155	fn num_cast_from(val: U) -> Self {
156		val
157	}
158}