1use core::fmt;
19
20use crate::error::WidthError;
21use crate::field::Bits;
22
23#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
43pub struct UInt<T, const N: usize> {
44 value: T,
45}
46
47macro_rules! impl_uint {
48 ($($t:ty),* $(,)?) => {
49 $(
50 impl<const N: usize> UInt<$t, N> {
51 pub const BITS: u32 = <Self as Bits>::BITS;
53
54 pub const MASK: $t = if N >= <$t>::BITS as usize {
56 <$t>::MAX
57 } else {
58 ((1 as $t) << N) - 1
59 };
60
61 pub const MAX: Self = Self { value: Self::MASK };
63
64 pub const MIN: Self = Self { value: 0 };
66
67 #[inline]
72 pub const fn new(value: $t) -> Self {
73 assert!(value <= Self::MASK, "value out of range for this width");
74 Self { value }
75 }
76
77 #[inline]
80 pub fn try_new(value: $t) -> core::result::Result<Self, WidthError> {
81 if value <= Self::MASK {
82 Ok(Self { value })
83 } else {
84 Err(WidthError::ValueTooLarge {
85 value: value as u128,
86 bits: N as u32,
87 })
88 }
89 }
90
91 #[inline]
94 pub const fn from_raw(value: $t) -> Self {
95 Self { value: value & Self::MASK }
96 }
97
98 #[inline]
100 pub const fn value(self) -> $t {
101 self.value
102 }
103
104 #[doc(hidden)]
109 #[inline]
110 pub const fn __bnb_from_bits(raw: u128) -> Self {
111 Self::from_raw(raw as $t)
112 }
113
114 #[doc(hidden)]
115 #[inline]
116 pub const fn __bnb_into_bits(self) -> u128 {
117 self.value as u128
118 }
119 }
120
121 impl<const N: usize> Default for UInt<$t, N> {
122 #[inline]
123 fn default() -> Self {
124 Self { value: 0 }
125 }
126 }
127
128 impl<const N: usize> Bits for UInt<$t, N> {
129 const BITS: u32 = N as u32;
130
131 #[inline]
132 fn into_bits(self) -> u128 {
133 self.__bnb_into_bits()
134 }
135
136 #[inline]
137 fn from_bits(raw: u128) -> Self {
138 Self::__bnb_from_bits(raw)
139 }
140 }
141
142 impl<const N: usize> fmt::Debug for UInt<$t, N> {
143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144 write!(f, "u{N}({})", self.value)
145 }
146 }
147
148 impl<const N: usize> fmt::Display for UInt<$t, N> {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150 fmt::Display::fmt(&self.value, f)
151 }
152 }
153
154 impl<const N: usize> From<UInt<$t, N>> for $t {
155 #[inline]
156 fn from(v: UInt<$t, N>) -> $t {
157 v.value
158 }
159 }
160
161 impl<const N: usize> TryFrom<$t> for UInt<$t, N> {
162 type Error = WidthError;
163 #[inline]
164 fn try_from(value: $t) -> core::result::Result<Self, WidthError> {
165 Self::try_new(value)
166 }
167 }
168 )*
169 };
170}
171
172impl_uint!(u8, u16, u32, u64, u128);
173
174#[rustfmt::skip]
184#[allow(non_camel_case_types, missing_docs)] mod aliases {
186 use super::UInt;
187
188 pub type u1 = UInt<u8, 1>; pub type u2 = UInt<u8, 2>; pub type u3 = UInt<u8, 3>;
190 pub type u4 = UInt<u8, 4>; pub type u5 = UInt<u8, 5>; pub type u6 = UInt<u8, 6>;
191 pub type u7 = UInt<u8, 7>;
192
193 pub type u9 = UInt<u16, 9>; pub type u10 = UInt<u16, 10>; pub type u11 = UInt<u16, 11>;
195 pub type u12 = UInt<u16, 12>; pub type u13 = UInt<u16, 13>; pub type u14 = UInt<u16, 14>;
196 pub type u15 = UInt<u16, 15>;
197
198 pub type u17 = UInt<u32, 17>; pub type u18 = UInt<u32, 18>; pub type u19 = UInt<u32, 19>;
200 pub type u20 = UInt<u32, 20>; pub type u21 = UInt<u32, 21>; pub type u22 = UInt<u32, 22>;
201 pub type u23 = UInt<u32, 23>; pub type u24 = UInt<u32, 24>; pub type u25 = UInt<u32, 25>;
202 pub type u26 = UInt<u32, 26>; pub type u27 = UInt<u32, 27>; pub type u28 = UInt<u32, 28>;
203 pub type u29 = UInt<u32, 29>; pub type u30 = UInt<u32, 30>; pub type u31 = UInt<u32, 31>;
204
205 pub type u33 = UInt<u64, 33>; pub type u34 = UInt<u64, 34>; pub type u35 = UInt<u64, 35>;
207 pub type u36 = UInt<u64, 36>; pub type u37 = UInt<u64, 37>; pub type u38 = UInt<u64, 38>;
208 pub type u39 = UInt<u64, 39>; pub type u40 = UInt<u64, 40>; pub type u41 = UInt<u64, 41>;
209 pub type u42 = UInt<u64, 42>; pub type u43 = UInt<u64, 43>; pub type u44 = UInt<u64, 44>;
210 pub type u45 = UInt<u64, 45>; pub type u46 = UInt<u64, 46>; pub type u47 = UInt<u64, 47>;
211 pub type u48 = UInt<u64, 48>; pub type u49 = UInt<u64, 49>; pub type u50 = UInt<u64, 50>;
212 pub type u51 = UInt<u64, 51>; pub type u52 = UInt<u64, 52>; pub type u53 = UInt<u64, 53>;
213 pub type u54 = UInt<u64, 54>; pub type u55 = UInt<u64, 55>; pub type u56 = UInt<u64, 56>;
214 pub type u57 = UInt<u64, 57>; pub type u58 = UInt<u64, 58>; pub type u59 = UInt<u64, 59>;
215 pub type u60 = UInt<u64, 60>; pub type u61 = UInt<u64, 61>; pub type u62 = UInt<u64, 62>;
216 pub type u63 = UInt<u64, 63>;
217
218 pub type u65 = UInt<u128, 65>; pub type u66 = UInt<u128, 66>; pub type u67 = UInt<u128, 67>;
220 pub type u68 = UInt<u128, 68>; pub type u69 = UInt<u128, 69>; pub type u70 = UInt<u128, 70>;
221 pub type u71 = UInt<u128, 71>; pub type u72 = UInt<u128, 72>; pub type u73 = UInt<u128, 73>;
222 pub type u74 = UInt<u128, 74>; pub type u75 = UInt<u128, 75>; pub type u76 = UInt<u128, 76>;
223 pub type u77 = UInt<u128, 77>; pub type u78 = UInt<u128, 78>; pub type u79 = UInt<u128, 79>;
224 pub type u80 = UInt<u128, 80>; pub type u81 = UInt<u128, 81>; pub type u82 = UInt<u128, 82>;
225 pub type u83 = UInt<u128, 83>; pub type u84 = UInt<u128, 84>; pub type u85 = UInt<u128, 85>;
226 pub type u86 = UInt<u128, 86>; pub type u87 = UInt<u128, 87>; pub type u88 = UInt<u128, 88>;
227 pub type u89 = UInt<u128, 89>; pub type u90 = UInt<u128, 90>; pub type u91 = UInt<u128, 91>;
228 pub type u92 = UInt<u128, 92>; pub type u93 = UInt<u128, 93>; pub type u94 = UInt<u128, 94>;
229 pub type u95 = UInt<u128, 95>; pub type u96 = UInt<u128, 96>; pub type u97 = UInt<u128, 97>;
230 pub type u98 = UInt<u128, 98>; pub type u99 = UInt<u128, 99>; pub type u100 = UInt<u128, 100>;
231 pub type u101 = UInt<u128, 101>; pub type u102 = UInt<u128, 102>; pub type u103 = UInt<u128, 103>;
232 pub type u104 = UInt<u128, 104>; pub type u105 = UInt<u128, 105>; pub type u106 = UInt<u128, 106>;
233 pub type u107 = UInt<u128, 107>; pub type u108 = UInt<u128, 108>; pub type u109 = UInt<u128, 109>;
234 pub type u110 = UInt<u128, 110>; pub type u111 = UInt<u128, 111>; pub type u112 = UInt<u128, 112>;
235 pub type u113 = UInt<u128, 113>; pub type u114 = UInt<u128, 114>; pub type u115 = UInt<u128, 115>;
236 pub type u116 = UInt<u128, 116>; pub type u117 = UInt<u128, 117>; pub type u118 = UInt<u128, 118>;
237 pub type u119 = UInt<u128, 119>; pub type u120 = UInt<u128, 120>; pub type u121 = UInt<u128, 121>;
238 pub type u122 = UInt<u128, 122>; pub type u123 = UInt<u128, 123>; pub type u124 = UInt<u128, 124>;
239 pub type u125 = UInt<u128, 125>; pub type u126 = UInt<u128, 126>; pub type u127 = UInt<u128, 127>;
240}
241
242pub use aliases::*;
243
244#[cfg(test)]
245mod unit {
246 use super::*;
247
248 #[test]
249 fn construction_and_range() {
250 assert_eq!(u5::MAX.value(), 31);
251 assert_eq!(u5::MIN.value(), 0);
252 assert_eq!(u5::new(17).value(), 17);
253 assert!(u5::try_new(31).is_ok());
254 assert!(u5::try_new(32).is_err());
255 assert_eq!(u5::from_raw(0xFF).value(), 31);
257 }
258
259 #[test]
260 #[should_panic(expected = "value out of range")]
261 fn new_panics_on_overflow() {
262 let _ = u4::new(16);
263 }
264
265 #[test]
266 fn bits_round_trip() {
267 let v = u13::new(0x1ABC & 0x1FFF);
268 assert_eq!(<u13 as Bits>::BITS, 13);
269 assert_eq!(u13::from_bits(v.into_bits()), v);
270 assert!(v.into_bits() <= u13::MAX.value() as u128);
272 }
273
274 #[test]
275 fn conversions() {
276 let v = u12::new(0xABC);
277 let raw: u16 = v.into();
278 assert_eq!(raw, 0xABC);
279 assert_eq!(u12::try_from(0xABCu16).unwrap(), v);
280 assert!(u12::try_from(0x1000u16).is_err());
281 }
282
283 #[test]
284 fn widest_widths_work() {
285 assert_eq!(u127::MAX.value(), (1u128 << 127) - 1);
286 assert_eq!(u1::MAX.value(), 1);
287 }
288
289 #[test]
290 fn display_renders_the_plain_value() {
291 use alloc::string::ToString;
292 assert_eq!(u12::new(0xABC).to_string(), "2748");
293 assert_eq!(u5::new(0).to_string(), "0");
294 }
295
296 #[test]
297 fn debug_shows_the_width_and_value() {
298 use alloc::format;
299 assert_eq!(format!("{:?}", u4::new(0xA)), "u4(10)");
300 assert_eq!(format!("{:?}", u12::new(0xABC)), "u12(2748)");
301 }
302}