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