ark_ff_macros/
utils.rs

1use std::str::FromStr;
2
3use num_bigint::{BigInt, Sign};
4use num_traits::Num;
5use proc_macro::TokenStream;
6use syn::{Expr, Lit};
7
8pub fn parse_string(input: TokenStream) -> Option<String> {
9    let input: Expr = syn::parse(input).unwrap();
10    let input = if let Expr::Group(syn::ExprGroup { expr, .. }) = input {
11        expr
12    } else {
13        panic!("could not parse");
14    };
15    match *input {
16        Expr::Lit(expr_lit) => match expr_lit.lit {
17            Lit::Str(s) => Some(s.value()),
18            _ => None,
19        },
20        _ => None,
21    }
22}
23
24pub fn str_to_limbs(num: &str) -> (bool, Vec<String>) {
25    let (sign, limbs) = str_to_limbs_u64(num);
26    (sign, limbs.into_iter().map(|l| format!("{l}u64")).collect())
27}
28
29pub fn str_to_limbs_u64(num: &str) -> (bool, Vec<u64>) {
30    let is_negative = num.starts_with('-');
31    let num = if is_negative { &num[1..] } else { num };
32    let number = if num.starts_with("0x") || num.starts_with("0X") {
33        // We are in hexadecimal
34        BigInt::from_str_radix(&num[2..], 16)
35    } else if num.starts_with("0o") || num.starts_with("0O") {
36        // We are in octal
37        BigInt::from_str_radix(&num[2..], 8)
38    } else if num.starts_with("0b") || num.starts_with("0B") {
39        // We are in binary
40        BigInt::from_str_radix(&num[2..], 2)
41    } else {
42        // We are in decimal
43        BigInt::from_str(num)
44    }
45    .expect("could not parse to bigint");
46    let number = if is_negative { -number } else { number };
47    let (sign, digits) = number.to_radix_le(16);
48
49    let limbs = digits
50        .chunks(16)
51        .map(|chunk| {
52            let mut this = 0u64;
53            for (i, hexit) in chunk.iter().enumerate() {
54                this += (*hexit as u64) << (4 * i);
55            }
56            this
57        })
58        .collect::<Vec<_>>();
59
60    let sign_is_positive = sign != Sign::Minus;
61    (sign_is_positive, limbs)
62}