1mod cmp;
8mod consts;
9mod convert;
10mod fmt;
11mod ops;
12
13use num_traits::{PrimInt, Unsigned};
14
15#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
50#[repr(transparent)]
51pub struct BitUint<T: Unsigned + PrimInt, const N: u32>(T);
52
53macro_rules! impl_bit_uint {
54 ($T:ty, $alias:ident) => {
55 impl<const N: u32> BitUint<$T, N> {
56 #[doc = concat!("let n = BitUint::<", stringify!($T), ", 6>::new(42);")]
66 #[doc = ""]
68 #[doc = concat!("let m = BitUint::<", stringify!($T), ", 5>::new(42);")]
69 #[must_use]
72 #[inline]
73 pub const fn new(n: $T) -> Option<Self> {
74 debug_assert!(n >= Self::MIN.get());
76
77 if n <= Self::MAX.get() {
78 let n = unsafe { Self::new_unchecked(n) };
80 Some(n)
81 } else {
82 None
83 }
84 }
85 }
86
87 #[doc = concat!("[`", stringify!($T), "`].")]
89 #[doc = concat!("The largest size of `N` is equal to [`", stringify!($T), "::BITS`].")]
91 pub type $alias<const N: u32> = BitUint<$T, N>;
92 };
93}
94impl_bit_uint!(u8, BitU8);
95impl_bit_uint!(u16, BitU16);
96impl_bit_uint!(u32, BitU32);
97impl_bit_uint!(u64, BitU64);
98impl_bit_uint!(u128, BitU128);
99impl_bit_uint!(usize, BitUsize);
100
101impl<T: Unsigned + PrimInt, const N: u32> BitUint<T, N> {
102 #[must_use]
112 #[inline]
113 pub const unsafe fn new_unchecked(n: T) -> Self {
114 Self(n)
115 }
116
117 #[must_use]
119 #[inline]
120 pub const fn get(self) -> T {
121 self.0
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use core::{any, mem};
128
129 use super::*;
130
131 #[test]
132 fn alias() {
133 assert_eq!(
134 any::type_name::<BitU8::<7>>(),
135 any::type_name::<BitUint::<u8, 7>>()
136 );
137 assert_eq!(
138 any::type_name::<BitU16::<15>>(),
139 any::type_name::<BitUint::<u16, 15>>()
140 );
141 assert_eq!(
142 any::type_name::<BitU32::<31>>(),
143 any::type_name::<BitUint::<u32, 31>>()
144 );
145 assert_eq!(
146 any::type_name::<BitU64::<63>>(),
147 any::type_name::<BitUint::<u64, 63>>()
148 );
149 assert_eq!(
150 any::type_name::<BitU128::<127>>(),
151 any::type_name::<BitUint::<u128, 127>>()
152 );
153 assert_eq!(
154 any::type_name::<BitUsize::<31>>(),
155 any::type_name::<BitUint::<usize, 31>>()
156 );
157 }
158
159 #[test]
160 fn layout() {
161 assert_eq!(mem::size_of::<BitU32::<31>>(), mem::size_of::<u32>());
162 assert_eq!(mem::align_of::<BitU32::<31>>(), mem::align_of::<u32>());
163 }
164
165 #[test]
166 fn clone() {
167 assert_eq!(BitU32::<31>::MIN.clone(), BitU32::<31>::MIN);
168 }
169
170 #[test]
171 fn copy() {
172 let a = BitU32::<31>::MIN;
173 let b = a;
174 assert_eq!(a, b);
175 }
176
177 #[test]
178 fn default() {
179 assert_eq!(
180 BitU32::<31>::default(),
181 BitU32::<31>::new(u32::default()).unwrap()
182 );
183 }
184
185 #[test]
186 fn new() {
187 assert_eq!(
188 BitU8::<7>::new(u8::MAX >> 1).map(BitU8::get),
189 Some(u8::MAX >> 1)
190 );
191 assert_eq!(
192 BitU16::<15>::new(u16::MAX >> 1).map(BitU16::get),
193 Some(u16::MAX >> 1)
194 );
195 assert_eq!(
196 BitU32::<31>::new(u32::MAX >> 1).map(BitU32::get),
197 Some(u32::MAX >> 1)
198 );
199 assert_eq!(
200 BitU64::<63>::new(u64::MAX >> 1).map(BitU64::get),
201 Some(u64::MAX >> 1)
202 );
203 assert_eq!(
204 BitU128::<127>::new(u128::MAX >> 1).map(BitU128::get),
205 Some(u128::MAX >> 1)
206 );
207 assert_eq!(
208 BitUsize::<{ usize::BITS - 1 }>::new(usize::MAX >> 1).map(BitUsize::get),
209 Some(usize::MAX >> 1)
210 );
211 }
212
213 #[test]
214 fn new_with_invalid_value() {
215 assert!(BitU8::<7>::new((u8::MAX >> 1) + 1).is_none());
216 assert!(BitU16::<15>::new((u16::MAX >> 1) + 1).is_none());
217 assert!(BitU32::<31>::new((u32::MAX >> 1) + 1).is_none());
218 assert!(BitU64::<63>::new((u64::MAX >> 1) + 1).is_none());
219 assert!(BitU128::<127>::new((u128::MAX >> 1) + 1).is_none());
220 assert!(BitUsize::<{ usize::BITS - 1 }>::new((usize::MAX >> 1) + 1).is_none());
221 }
222
223 #[test]
224 fn new_when_one_bit_value() {
225 assert_eq!(BitU32::<1>::new(0).map(BitU32::get), Some(0));
226 assert_eq!(BitU32::<1>::new(1).map(BitU32::get), Some(1));
227 assert!(BitU32::<1>::new(2).is_none());
228 }
229
230 #[test]
231 fn new_when_max_bits_value() {
232 assert_eq!(
233 BitU32::<{ u32::BITS }>::new(u32::MIN).map(BitU32::get),
234 Some(u32::MIN)
235 );
236 assert_eq!(
237 BitU32::<{ u32::BITS }>::new(u32::MAX).map(BitU32::get),
238 Some(u32::MAX)
239 );
240 }
241
242 #[test]
243 const fn new_is_const_fn() {
244 const _: Option<BitU32<31>> = BitU32::<31>::new(u32::MAX >> 1);
245 }
246
247 #[test]
248 fn new_unchecked() {
249 assert_eq!(
250 unsafe { BitU8::<7>::new_unchecked(u8::MAX >> 1) }.get(),
251 u8::MAX >> 1
252 );
253 assert_eq!(
254 unsafe { BitU16::<15>::new_unchecked(u16::MAX >> 1) }.get(),
255 u16::MAX >> 1
256 );
257 assert_eq!(
258 unsafe { BitU32::<31>::new_unchecked(u32::MAX >> 1) }.get(),
259 u32::MAX >> 1
260 );
261 assert_eq!(
262 unsafe { BitU64::<63>::new_unchecked(u64::MAX >> 1) }.get(),
263 u64::MAX >> 1
264 );
265 assert_eq!(
266 unsafe { BitU128::<127>::new_unchecked(u128::MAX >> 1) }.get(),
267 u128::MAX >> 1
268 );
269 assert_eq!(
270 unsafe { BitUsize::<{ usize::BITS - 1 }>::new_unchecked(usize::MAX >> 1) }.get(),
271 usize::MAX >> 1
272 );
273 }
274
275 #[test]
276 const fn new_unchecked_is_const_fn() {
277 const _: BitU32<31> = unsafe { BitU32::<31>::new_unchecked(u32::MAX >> 1) };
278 }
279
280 #[test]
281 fn get() {
282 assert_eq!(BitU8::<7>::MAX.get(), u8::MAX >> 1);
283 assert_eq!(BitU16::<15>::MAX.get(), u16::MAX >> 1);
284 assert_eq!(BitU32::<31>::MAX.get(), u32::MAX >> 1);
285 assert_eq!(BitU64::<63>::MAX.get(), u64::MAX >> 1);
286 assert_eq!(BitU128::<127>::MAX.get(), u128::MAX >> 1);
287 assert_eq!(BitUsize::<{ usize::BITS - 1 }>::MAX.get(), usize::MAX >> 1);
288 }
289
290 #[test]
291 const fn get_is_const_fn() {
292 const _: u32 = BitU32::<31>::MIN.get();
293 }
294}