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