use std::{
fmt::Write as FmtWrite,
fs::File,
io::{BufWriter, Write},
path::PathBuf,
};
use rustc_version::{version_meta, Channel};
fn u(mut i: u128) -> String {
let mut result = "UTerm".into();
let mut ids = Vec::new();
while i > 0 {
let bit = i & 1;
ids.push(bit as u8);
i >>= 1;
}
for bit in ids.into_iter().rev() {
result = format!("UInt<{result}, B{bit}>");
}
result
}
fn typenum_unsigned() -> std::io::Result<()> {
const SEQ_MAX: u128 = 1000;
let filename = PathBuf::from(std::env::var_os("OUT_DIR").unwrap()).join("unsigned.rs");
let mut file = BufWriter::new(File::create(filename).unwrap());
for i in 0..=SEQ_MAX {
let u = u(i);
writeln!(file, "/// {i}\npub type U{i} = {u};")?;
writeln!(file, "/// {i}\npub type Ux{i:X} = {u};")?;
writeln!(file, "/// {i}\npub type Ub{i:b} = {u};")?;
}
for i in 0..39 {
let ipow = 10u128.pow(i);
let u = u(ipow);
writeln!(file, "/// {i}\npub type U10pow{i} = {u};")?;
if ipow > SEQ_MAX {
writeln!(file, "/// {i}\npub type U{ipow} = {u};")?;
writeln!(file, "/// {i}\npub type Ux{ipow:X} = {u};")?;
writeln!(file, "/// {i}\npub type Ub{ipow:b} = {u};")?;
}
}
for i in 0..128 {
let p = 1 << i;
let u = u(p);
writeln!(file, "/// {i}\npub type U2pow{i} = {u};")?;
if p > SEQ_MAX {
writeln!(file, "/// {i}\npub type U{p} = {u};")?;
}
}
Ok(())
}
fn tuples(max_tuple: usize) -> std::io::Result<()> {
let filename = PathBuf::from(std::env::var_os("OUT_DIR").unwrap()).join("tuples.rs");
let mut file = BufWriter::new(File::create(filename).unwrap());
for i in 0..=max_tuple {
writeln!(
file,
r##"/// An ABI stable tuple of {i} elements.
#[crate::stabby]
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Tuple{i}<{generics}>({fields});
impl<{generics}> From<({generics})> for Tuple{i}<{generics}> {{
fn from(value: ({generics})) -> Self {{
let ({named_fields}) = value;
Self({named_fields})
}}
}}
#[allow(clippy::unused_unit)]
impl<{generics}> From<Tuple{i}<{generics}>> for ({generics}) {{
fn from(value: Tuple{i}<{generics}>) -> Self {{
let Tuple{i}({named_fields}) = value;
({named_fields})
}}
}}
"##,
generics = (0..i).fold(String::new(), |mut acc, it| {
write!(acc, "T{it}, ").unwrap();
acc
}),
fields = (0..i).fold(String::new(), |mut acc, it| {
write!(acc, "pub T{it}, ").unwrap();
acc
}),
named_fields = (0..i).fold(String::new(), |mut acc, it| {
write!(acc, "field{it}, ").unwrap();
acc
}),
)?;
}
Ok(())
}
fn main() {
typenum_unsigned().unwrap();
println!("cargo:rustc-check-cfg=cfg(stabby_max_tuple, values(any()))");
let max_tuple = std::env::var("CARGO_CFG_STABBY_MAX_TUPLE")
.map_or(32, |s| s.parse().unwrap_or(32))
.max(10);
tuples(max_tuple).unwrap();
println!("cargo:rustc-check-cfg=cfg(stabby_nightly, values(none()))");
println!(
r#"cargo:rustc-check-cfg=cfg(stabby_default_alloc, values("RustAlloc", "LibcAlloc", "disabled"))"#
);
println!(
r#"cargo:rustc-check-cfg=cfg(stabby_check_unreachable, values(none(), "true", "false"))"#
);
println!(r#"cargo:rustc-check-cfg=cfg(stabby_unsafe_wakers, values(none(), "true", "false"))"#);
println!(
r#"cargo:rustc-check-cfg=cfg(stabby_vtables, values(none(), "vec", "btree", "no_alloc"))"#
);
if std::env::var("CARGO_CFG_STABBY_DEFAULT_ALLOC").is_err() {
if std::env::var("CARGO_FEATURE_ALLOC_RS").is_ok() {
println!(r#"cargo:rustc-cfg=stabby_default_alloc="RustAlloc""#);
} else if std::env::var("CARGO_FEATURE_LIBC").is_ok() {
println!(r#"cargo:rustc-cfg=stabby_default_alloc="LibcAlloc""#);
} else {
println!(r#"cargo:rustc-cfg=stabby_default_alloc="disabled""#);
}
}
if let Channel::Nightly = version_meta().unwrap().channel {
println!("cargo:rustc-cfg=stabby_nightly");
}
}