1 use std::env;
2 use std::error::Error;
3 use std::fs::File;
4 use std::io::Write;
5 use std::path::Path;
6 
main()7 fn main() {
8     let pointer_width = env::var("CARGO_CFG_TARGET_POINTER_WIDTH");
9     let u64_digit = pointer_width.as_ref().map(String::as_str) == Ok("64");
10     if u64_digit {
11         autocfg::emit("u64_digit");
12     }
13     let ac = autocfg::new();
14     let std = if ac.probe_sysroot_crate("std") {
15         "std"
16     } else {
17         "core"
18     };
19     if ac.probe_path(&format!("{}::convert::TryFrom", std)) {
20         autocfg::emit("has_try_from");
21     }
22 
23     if let Ok(target_arch) = env::var("CARGO_CFG_TARGET_ARCH") {
24         if target_arch == "x86_64" || target_arch == "x86" {
25             let digit = if u64_digit { "u64" } else { "u32" };
26 
27             let addcarry = format!("{}::arch::{}::_addcarry_{}", std, target_arch, digit);
28             if ac.probe_path(&addcarry) {
29                 autocfg::emit("use_addcarry");
30             }
31         }
32     }
33 
34     autocfg::rerun_path("build.rs");
35 
36     write_radix_bases().unwrap();
37 }
38 
39 /// Write tables of the greatest power of each radix for the given bit size.  These are returned
40 /// from `biguint::get_radix_base` to batch the multiplication/division of radix conversions on
41 /// full `BigUint` values, operating on primitive integers as much as possible.
42 ///
43 /// e.g. BASES_16[3] = (59049, 10) // 3¹⁰ fits in u16, but 3¹¹ is too big
44 ///      BASES_32[3] = (3486784401, 20)
45 ///      BASES_64[3] = (12157665459056928801, 40)
46 ///
47 /// Powers of two are not included, just zeroed, as they're implemented with shifts.
write_radix_bases() -> Result<(), Box<dyn Error>>48 fn write_radix_bases() -> Result<(), Box<dyn Error>> {
49     let out_dir = env::var("OUT_DIR")?;
50     let dest_path = Path::new(&out_dir).join("radix_bases.rs");
51     let mut f = File::create(&dest_path)?;
52 
53     for &bits in &[16, 32, 64] {
54         let max = if bits < 64 {
55             (1 << bits) - 1
56         } else {
57             std::u64::MAX
58         };
59 
60         writeln!(f, "#[deny(overflowing_literals)]")?;
61         writeln!(
62             f,
63             "pub(crate) static BASES_{bits}: [(u{bits}, usize); 257] = [",
64             bits = bits
65         )?;
66         for radix in 0u64..257 {
67             let (base, power) = if radix == 0 || radix.is_power_of_two() {
68                 (0, 0)
69             } else {
70                 let mut power = 1;
71                 let mut base = radix;
72 
73                 while let Some(b) = base.checked_mul(radix) {
74                     if b > max {
75                         break;
76                     }
77                     base = b;
78                     power += 1;
79                 }
80                 (base, power)
81             };
82             writeln!(f, "    ({}, {}), // {}", base, power, radix)?;
83         }
84         writeln!(f, "];")?;
85     }
86 
87     Ok(())
88 }
89