1mod cmp;
8mod consts;
9mod convert;
10mod fmt;
11mod ops;
12
13use num_traits::{PrimInt, Signed};
14
15#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
50#[repr(transparent)]
51pub struct BitInt<T: Signed + PrimInt, const N: u32>(T);
52
53macro_rules! impl_bit_int {
54 ($T:ty, $alias:ident) => {
55 impl<const N: u32> BitInt<$T, N> {
56 #[doc = concat!("let n = BitInt::<", stringify!($T), ", 7>::new(42);")]
66 #[doc = ""]
68 #[doc = concat!("let m = BitInt::<", stringify!($T), ", 6>::new(42);")]
69 #[must_use]
72 #[inline]
73 pub const fn new(n: $T) -> Option<Self> {
74 if n >= Self::MIN.get() && n <= Self::MAX.get() {
75 let n = unsafe { Self::new_unchecked(n) };
77 Some(n)
78 } else {
79 None
80 }
81 }
82
83 #[doc = concat!("assert_eq!(BitInt::<", stringify!($T), ", 7>::MIN.is_positive(), false);")]
92 #[doc = concat!("assert_eq!(BitInt::<", stringify!($T), ", 7>::MAX.is_positive(), true);")]
93 #[must_use]
95 #[inline]
96 pub const fn is_positive(self) -> bool {
97 self.get().is_positive()
98 }
99
100 #[doc = concat!("assert_eq!(BitInt::<", stringify!($T), ", 7>::MIN.is_negative(), true);")]
109 #[doc = concat!("assert_eq!(BitInt::<", stringify!($T), ", 7>::MAX.is_negative(), false);")]
110 #[must_use]
112 #[inline]
113 pub const fn is_negative(self) -> bool {
114 self.get().is_negative()
115 }
116 }
117
118 #[doc = concat!("[`", stringify!($T), "`].")]
120 #[doc = concat!("The largest size of `N` is equal to [`", stringify!($T), "::BITS`].")]
122 pub type $alias<const N: u32> = BitInt<$T, N>;
123 };
124}
125impl_bit_int!(i8, BitI8);
126impl_bit_int!(i16, BitI16);
127impl_bit_int!(i32, BitI32);
128impl_bit_int!(i64, BitI64);
129impl_bit_int!(i128, BitI128);
130impl_bit_int!(isize, BitIsize);
131
132impl<T: Signed + PrimInt, const N: u32> BitInt<T, N> {
133 #[must_use]
143 #[inline]
144 pub const unsafe fn new_unchecked(n: T) -> Self {
145 Self(n)
146 }
147
148 #[must_use]
150 #[inline]
151 pub const fn get(self) -> T {
152 self.0
153 }
154}
155
156#[cfg(test)]
157mod tests {
158 use core::{any, mem};
159
160 use super::*;
161
162 #[test]
163 fn alias() {
164 assert_eq!(
165 any::type_name::<BitI8::<7>>(),
166 any::type_name::<BitInt::<i8, 7>>()
167 );
168 assert_eq!(
169 any::type_name::<BitI16::<15>>(),
170 any::type_name::<BitInt::<i16, 15>>()
171 );
172 assert_eq!(
173 any::type_name::<BitI32::<31>>(),
174 any::type_name::<BitInt::<i32, 31>>()
175 );
176 assert_eq!(
177 any::type_name::<BitI64::<63>>(),
178 any::type_name::<BitInt::<i64, 63>>()
179 );
180 assert_eq!(
181 any::type_name::<BitI128::<127>>(),
182 any::type_name::<BitInt::<i128, 127>>()
183 );
184 assert_eq!(
185 any::type_name::<BitIsize::<31>>(),
186 any::type_name::<BitInt::<isize, 31>>()
187 );
188 }
189
190 #[test]
191 fn layout() {
192 assert_eq!(mem::size_of::<BitI32::<31>>(), mem::size_of::<i32>());
193 assert_eq!(mem::align_of::<BitI32::<31>>(), mem::align_of::<i32>());
194 }
195
196 #[test]
197 fn clone() {
198 assert_eq!(BitI32::<31>::MIN.clone(), BitI32::<31>::MIN);
199 }
200
201 #[test]
202 fn copy() {
203 let a = BitI32::<31>::MIN;
204 let b = a;
205 assert_eq!(a, b);
206 }
207
208 #[test]
209 fn default() {
210 assert_eq!(
211 BitI32::<31>::default(),
212 BitI32::<31>::new(i32::default()).unwrap()
213 );
214 }
215
216 #[test]
217 fn new() {
218 assert_eq!(
219 BitI8::<7>::new(i8::MAX >> 1).map(BitI8::get),
220 Some(i8::MAX >> 1)
221 );
222 assert_eq!(
223 BitI16::<15>::new(i16::MAX >> 1).map(BitI16::get),
224 Some(i16::MAX >> 1)
225 );
226 assert_eq!(
227 BitI32::<31>::new(i32::MAX >> 1).map(BitI32::get),
228 Some(i32::MAX >> 1)
229 );
230 assert_eq!(
231 BitI64::<63>::new(i64::MAX >> 1).map(BitI64::get),
232 Some(i64::MAX >> 1)
233 );
234 assert_eq!(
235 BitI128::<127>::new(i128::MAX >> 1).map(BitI128::get),
236 Some(i128::MAX >> 1)
237 );
238 assert_eq!(
239 BitIsize::<{ isize::BITS - 1 }>::new(isize::MAX >> 1).map(BitIsize::get),
240 Some(isize::MAX >> 1)
241 );
242 }
243
244 #[test]
245 fn new_with_invalid_value() {
246 assert!(BitI8::<7>::new((i8::MAX >> 1) + 1).is_none());
247 assert!(BitI16::<15>::new((i16::MAX >> 1) + 1).is_none());
248 assert!(BitI32::<31>::new((i32::MAX >> 1) + 1).is_none());
249 assert!(BitI64::<63>::new((i64::MAX >> 1) + 1).is_none());
250 assert!(BitI128::<127>::new((i128::MAX >> 1) + 1).is_none());
251 assert!(BitIsize::<{ isize::BITS - 1 }>::new((isize::MAX >> 1) + 1).is_none());
252 }
253
254 #[test]
255 fn new_when_one_bit_value() {
256 assert!(BitI32::<1>::new(-2).is_none());
257 assert_eq!(BitI32::<1>::new(-1).map(BitI32::get), Some(-1));
258 assert_eq!(BitI32::<1>::new(0).map(BitI32::get), Some(0));
259 assert!(BitI32::<1>::new(1).is_none());
260 }
261
262 #[test]
263 fn new_when_max_bits_value() {
264 assert_eq!(
265 BitI32::<{ i32::BITS }>::new(i32::MIN).map(BitI32::get),
266 Some(i32::MIN)
267 );
268 assert_eq!(
269 BitI32::<{ i32::BITS }>::new(i32::default()).map(BitI32::get),
270 Some(i32::default())
271 );
272 assert_eq!(
273 BitI32::<{ i32::BITS }>::new(i32::MAX).map(BitI32::get),
274 Some(i32::MAX)
275 );
276 }
277
278 #[test]
279 const fn new_is_const_fn() {
280 const _: Option<BitI32<31>> = BitI32::<31>::new(i32::MAX >> 1);
281 }
282
283 #[test]
284 fn new_unchecked() {
285 assert_eq!(
286 unsafe { BitI8::<7>::new_unchecked(i8::MAX >> 1) }.get(),
287 i8::MAX >> 1
288 );
289 assert_eq!(
290 unsafe { BitI16::<15>::new_unchecked(i16::MAX >> 1) }.get(),
291 i16::MAX >> 1
292 );
293 assert_eq!(
294 unsafe { BitI32::<31>::new_unchecked(i32::MAX >> 1) }.get(),
295 i32::MAX >> 1
296 );
297 assert_eq!(
298 unsafe { BitI64::<63>::new_unchecked(i64::MAX >> 1) }.get(),
299 i64::MAX >> 1
300 );
301 assert_eq!(
302 unsafe { BitI128::<127>::new_unchecked(i128::MAX >> 1) }.get(),
303 i128::MAX >> 1
304 );
305 assert_eq!(
306 unsafe { BitIsize::<{ isize::BITS - 1 }>::new_unchecked(isize::MAX >> 1) }.get(),
307 isize::MAX >> 1
308 );
309 }
310
311 #[test]
312 const fn new_unchecked_is_const_fn() {
313 const _: BitI32<31> = unsafe { BitI32::<31>::new_unchecked(i32::MAX >> 1) };
314 }
315
316 #[test]
317 fn get() {
318 assert_eq!(BitI8::<7>::MAX.get(), i8::MAX >> 1);
319 assert_eq!(BitI16::<15>::MAX.get(), i16::MAX >> 1);
320 assert_eq!(BitI32::<31>::MAX.get(), i32::MAX >> 1);
321 assert_eq!(BitI64::<63>::MAX.get(), i64::MAX >> 1);
322 assert_eq!(BitI128::<127>::MAX.get(), i128::MAX >> 1);
323 assert_eq!(BitIsize::<{ isize::BITS - 1 }>::MAX.get(), isize::MAX >> 1);
324 }
325
326 #[test]
327 const fn get_is_const_fn() {
328 const _: i32 = BitI32::<31>::MIN.get();
329 }
330
331 #[test]
332 fn is_positive() {
333 assert!(!BitI32::<31>::MIN.is_positive());
334 assert!(!BitI32::<31>::default().is_positive());
335 assert!(BitI32::<31>::MAX.is_positive());
336 }
337
338 #[test]
339 const fn is_positive_is_const_fn() {
340 const _: bool = BitI32::<31>::MIN.is_positive();
341 }
342
343 #[test]
344 fn is_negative() {
345 assert!(BitI32::<31>::MIN.is_negative());
346 assert!(!BitI32::<31>::default().is_negative());
347 assert!(!BitI32::<31>::MAX.is_negative());
348 }
349
350 #[test]
351 const fn is_negative_is_const_fn() {
352 const _: bool = BitI32::<31>::MIN.is_positive();
353 }
354}