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
use num_bigint::BigInt;
use quote::{quote, ToTokens, TokenStreamExt};
use syn::Expr;

use num_traits::{Signed, ToPrimitive};
use proc_macro2::{Literal, TokenStream};

pub(crate) enum BigIntWrapper<'a> {
    Integer(BigInt),
    Constant(&'a Expr, usize),
}

impl<'a> From<BigInt> for BigIntWrapper<'a> {
    #[inline]
    fn from(v: BigInt) -> BigIntWrapper<'a> {
        BigIntWrapper::Integer(v)
    }
}

impl<'a> From<(&'a Expr, usize)> for BigIntWrapper<'a> {
    #[inline]
    fn from((expr, counter): (&'a Expr, usize)) -> BigIntWrapper<'a> {
        BigIntWrapper::Constant(expr, counter)
    }
}

impl<'a> ToTokens for BigIntWrapper<'a> {
    #[inline]
    fn to_tokens(&self, tokens: &mut TokenStream) {
        match self {
            BigIntWrapper::Integer(v) => {
                let lit = if v.is_negative() {
                    Literal::i128_unsuffixed(v.to_i128().unwrap())
                } else {
                    Literal::u128_unsuffixed(v.to_u128().unwrap())
                };

                tokens.append(lit);
            }
            BigIntWrapper::Constant(expr, counter) => {
                let counter = *counter;

                if counter > 0 {
                    tokens.extend(quote!(#expr +));
                    tokens.append(Literal::usize_unsuffixed(counter));
                } else {
                    tokens.extend(quote!(#expr));
                }
            }
        }
    }
}