ruint/
macros.rs

1/// Wrapper for [`ruint_macro::uint!`]. See its documentation for details.
2#[macro_export]
3#[cfg(not(doc))] // Show the actual macro in docs.
4#[doc(hidden)]
5macro_rules! uint {
6    ($($t:tt)*) => {
7        $crate::__private::ruint_macro::uint_with_path! { [$crate] $($t)* }
8    }
9}
10
11macro_rules! impl_bin_op {
12    ($trait:ident, $fn:ident, $trait_assign:ident, $fn_assign:ident, $fdel:ident) => {
13        impl<const BITS: usize, const LIMBS: usize> $trait_assign<Uint<BITS, LIMBS>>
14            for Uint<BITS, LIMBS>
15        {
16            #[inline(always)]
17            #[track_caller]
18            fn $fn_assign(&mut self, rhs: Uint<BITS, LIMBS>) {
19                *self = self.$fdel(rhs);
20            }
21        }
22        impl<const BITS: usize, const LIMBS: usize> $trait_assign<&Uint<BITS, LIMBS>>
23            for Uint<BITS, LIMBS>
24        {
25            #[inline(always)]
26            #[track_caller]
27            fn $fn_assign(&mut self, rhs: &Uint<BITS, LIMBS>) {
28                *self = self.$fdel(*rhs);
29            }
30        }
31        impl<const BITS: usize, const LIMBS: usize> $trait<Uint<BITS, LIMBS>>
32            for Uint<BITS, LIMBS>
33        {
34            type Output = Uint<BITS, LIMBS>;
35
36            #[inline(always)]
37            #[track_caller]
38            fn $fn(self, rhs: Uint<BITS, LIMBS>) -> Self::Output {
39                self.$fdel(rhs)
40            }
41        }
42        impl<const BITS: usize, const LIMBS: usize> $trait<&Uint<BITS, LIMBS>>
43            for Uint<BITS, LIMBS>
44        {
45            type Output = Uint<BITS, LIMBS>;
46
47            #[inline(always)]
48            #[track_caller]
49            fn $fn(self, rhs: &Uint<BITS, LIMBS>) -> Self::Output {
50                self.$fdel(*rhs)
51            }
52        }
53        impl<const BITS: usize, const LIMBS: usize> $trait<Uint<BITS, LIMBS>>
54            for &Uint<BITS, LIMBS>
55        {
56            type Output = Uint<BITS, LIMBS>;
57
58            #[inline(always)]
59            #[track_caller]
60            fn $fn(self, rhs: Uint<BITS, LIMBS>) -> Self::Output {
61                self.$fdel(rhs)
62            }
63        }
64        impl<const BITS: usize, const LIMBS: usize> $trait<&Uint<BITS, LIMBS>>
65            for &Uint<BITS, LIMBS>
66        {
67            type Output = Uint<BITS, LIMBS>;
68
69            #[inline(always)]
70            #[track_caller]
71            fn $fn(self, rhs: &Uint<BITS, LIMBS>) -> Self::Output {
72                self.$fdel(*rhs)
73            }
74        }
75    };
76}
77
78macro_rules! assume {
79    ($e:expr $(,)?) => {
80        if !$e {
81            debug_unreachable!(stringify!($e));
82        }
83    };
84
85    ($e:expr, $($t:tt)+) => {
86        if !$e {
87            debug_unreachable!($($t)+);
88        }
89    };
90}
91
92macro_rules! debug_unreachable {
93    ($($t:tt)*) => {
94        if cfg!(debug_assertions) {
95            unreachable!($($t)*);
96        } else {
97            unsafe { core::hint::unreachable_unchecked() };
98        }
99    };
100}
101
102/// `let $id = &mut [0u64; nlimbs(2 * BITS)][..]`
103macro_rules! let_double_bits {
104    ($id:ident) => {
105        // This array casting is a workaround for `generic_const_exprs` not being
106        // stable.
107        let mut double = [[0u64; 2]; LIMBS];
108        let double_len = crate::nlimbs(2 * BITS);
109        debug_assert!(2 * LIMBS >= double_len);
110        // SAFETY: `[[u64; 2]; LIMBS] == [u64; 2 * LIMBS] >= [u64; nlimbs(2 * BITS)]`.
111        let $id = unsafe {
112            core::slice::from_raw_parts_mut(double.as_mut_ptr().cast::<u64>(), double_len)
113        };
114    };
115}
116
117/// Specialize an operation for u64, u128, u256 ([u128; 2])...
118macro_rules! as_primitives {
119    ($uint:expr, { $($arm:ident $t:tt => $e:expr),* $(,)? }) => {
120        $(
121            as_primitives!(@arm $uint; $arm $t => $e);
122        )*
123    };
124
125    (@arm $uint:expr; u64($n:ident) => $e:expr) => {
126        if LIMBS == 1 {
127            let $n = $uint.limbs[0];
128            $e
129        }
130    };
131    (@arm $uint:expr; u128($n:ident) => $e:expr) => {
132        if LIMBS == 2 {
133            let $n = $uint.as_double_words()[0].get();
134            $e
135        }
136    };
137    (@arm $uint:expr; u256($lo:ident, $hi:ident) => $e:expr) => {
138        if LIMBS == 4 {
139            let &[lo, hi] = $uint.as_double_words() else { unreachable!() };
140            let $lo = lo.get();
141            let $hi = hi.get();
142            $e
143        }
144    };
145}
146
147#[cfg(test)]
148mod tests {
149    // https://github.com/recmo/uint/issues/359
150    ruint_macro::uint_with_path! {
151        [crate]
152        const _A: [crate::aliases::U256; 2] = [
153            0x00006f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad5_U256,
154            0x00004b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e8_U256,
155        ];
156    }
157
158    crate::uint! {
159        const _B: [crate::aliases::U256; 2] = [
160            0x00006f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad5_U256,
161            0x00004b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e8_U256,
162        ];
163    }
164
165    #[test]
166    fn test_uint_macro_with_paths() {
167        extern crate self as aaa;
168        use crate as ruint;
169        use crate as __ruint;
170        let value = crate::aliases::U256::from(0x10);
171        assert_eq!(value, uint!(0x10U256));
172        assert_eq!(value, ruint_macro::uint_with_path!([crate] 0x10U256));
173        assert_eq!(value, ruint_macro::uint_with_path!([aaa] 0x10U256));
174        assert_eq!(value, ruint_macro::uint_with_path!([aaa] 0x10U256));
175        assert_eq!(value, ruint_macro::uint_with_path!([ruint] 0x10U256));
176        assert_eq!(value, ruint_macro::uint_with_path!([__ruint] 0x10U256));
177    }
178}