1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// Copyright 2024 Ulvetanna Inc.

use super::{
	small_uint::{U1, U2, U4},
	underlier_type::{NumCast, UnderlierType},
	underlier_with_bit_ops::UnderlierWithBitOps,
};

macro_rules! impl_underlier_type {
	($name:ty) => {
		impl UnderlierType for $name {
			const LOG_BITS: usize =
				binius_utils::checked_arithmetics::checked_log_2(Self::BITS as _);
		}

        impl UnderlierWithBitOps for $name {
			const ZERO: Self = 0;
			const ONE: Self = 1;
			const ONES: Self = <$name>::MAX;

			#[inline(always)]
			fn fill_with_bit(val: u8) -> Self {
				debug_assert!(val == 0 || val == 1);
				(val as Self).wrapping_neg()
			}
		}
	};
	() => {};
	($name:ty, $($tail:ty),+) => {
		impl_underlier_type!($name);
		impl_underlier_type!($($tail),+);
	}
}

impl_underlier_type!(u8, u16, u32, u64, u128);

macro_rules! impl_num_cast {
	(@pair U1, U2) => {impl_num_cast!(@small_u_from_small_u U1, U2);};
	(@pair U1, U4) => {impl_num_cast!(@small_u_from_small_u U1, U4);};
	(@pair U2, U4) => {impl_num_cast!(@small_u_from_small_u U2, U4);};
	(@pair U1, $bigger:ty) => {impl_num_cast!(@small_u_from_u U1, $bigger);};
	(@pair U2, $bigger:ty) => {impl_num_cast!(@small_u_from_u U2, $bigger);};
	(@pair U4, $bigger:ty) => {impl_num_cast!(@small_u_from_u U4, $bigger);};
	(@pair $smaller:ident, $bigger:ident) => {
		impl NumCast<$bigger> for $smaller {
			#[inline(always)]
			fn num_cast_from(val: $bigger) -> Self {
				val as _
			}
		}

		impl NumCast<$smaller> for $bigger {
			#[inline(always)]
			fn num_cast_from(val: $smaller) -> Self {
				val as _
			}
		}
	};
	(@small_u_from_small_u $smaller:ty, $bigger:ty) => {
		impl NumCast<$bigger> for $smaller {
			#[inline(always)]
			fn num_cast_from(val: $bigger) -> Self {
				Self::new(val.val()) & Self::ONES
			}
		}

		impl NumCast<$smaller> for $bigger {
			#[inline(always)]
			fn num_cast_from(val: $smaller) -> Self {
				Self::new(val.val())
			}
		}
	};
	(@small_u_from_u $smaller:ty, $bigger:ty) => {
		impl NumCast<$bigger> for $smaller {
			#[inline(always)]
			fn num_cast_from(val: $bigger) -> Self {
				Self::new(val as u8) & Self::ONES
			}
		}

		impl NumCast<$smaller> for $bigger {
			#[inline(always)]
			fn num_cast_from(val: $smaller) -> Self {
				val.val() as _
			}
		}
	};
	($_:ty,) => {};
	(,) => {};
	(all_pairs) => {};
	(all_pairs $_:ty) => {};
	(all_pairs $_:ty,) => {};
	(all_pairs $smaller:ident, $head:ident, $($tail:ident,)*) => {
		impl_num_cast!(@pair $smaller, $head);
		impl_num_cast!(all_pairs $smaller, $($tail,)*);
	};
	($smaller:ident, $($tail:ident,)+) => {
		impl_num_cast!(all_pairs $smaller, $($tail,)+);
		impl_num_cast!($($tail,)+);
	};
}

impl_num_cast!(U1, U2, U4, u8, u16, u32, u64, u128,);