use std::{env, fmt::Write, fs, path::Path};
fn main() {
println!("cargo::rerun-if-changed=isodata.tsv");
let tsv = fs::read_to_string("isodata.tsv").expect("isodata.tsv is readable");
let mut consts = String::new();
let mut alpha_arms = String::new();
let mut numeric_arms = String::new();
let mut codes = Vec::new();
for line in tsv.lines().skip(1).filter(|l| !l.trim().is_empty()) {
let fields: Vec<&str> = line.split('\t').collect();
let (alpha, numeric, name, symbol, exponent) =
(fields[0], fields[1], fields[2], fields[4], fields[6]);
let flags = fields.get(7).copied().unwrap_or("");
assert!(
alpha.len() == 3 && alpha.bytes().all(|b| b.is_ascii_uppercase()),
"malformed alphabetic code: {alpha:?}"
);
assert!(!symbol.is_empty(), "missing symbol for {alpha}");
let numeric: u32 = numeric.parse().expect("numeric code");
let minor_digits: u32 = if exponent.is_empty() {
0
} else {
exponent.parse().expect("exponent")
};
let doc = match flags {
"" => format!("{name}."),
"fund" => format!("{name}; fund code."),
"special" => format!("{name}; special code."),
s if s.starts_with("superseded(") && s.ends_with(')') => {
format!("{name}; superseded by {}.", &s[11..s.len() - 1])
}
other => panic!("unrecognized flags column: {other:?}"),
};
writeln!(consts, " /// {doc}").unwrap();
writeln!(consts, " pub const {alpha}: Currency = Currency {{").unwrap();
writeln!(
consts,
" alphabetic_code: IsoAlphabeticCode(*b\"{alpha}\"),"
)
.unwrap();
writeln!(consts, " numeric_code: IsoNumericCode({numeric}),").unwrap();
writeln!(consts, " minor_digits: {minor_digits},").unwrap();
writeln!(consts, " symbol: {symbol:?},").unwrap();
writeln!(consts, " }};").unwrap();
writeln!(
alpha_arms,
" \"{alpha}\" => Some(Currency::{alpha}),"
)
.unwrap();
writeln!(
numeric_arms,
" {numeric} => Some(Currency::{alpha}),"
)
.unwrap();
codes.push(alpha.to_string());
}
let count = codes.len();
let table = codes
.iter()
.map(|c| format!(" Currency::{c},"))
.collect::<Vec<_>>()
.join("\n");
let code = format!(
"impl Currency {{
{consts}}}
const ISO_CURRENCIES: [Currency; {count}] = [
{table}
];
impl Currency {{
/// Every ISO 4217 currency, including fund, superseded, and special codes.
pub fn all() -> &'static [Currency] {{
&ISO_CURRENCIES
}}
/// Look up a currency by its three-letter code, e.g. `\"USD\"`. Case-sensitive.
pub fn from_alphabetic_code(code: &str) -> Option<Currency> {{
match code {{
{alpha_arms} _ => None,
}}
}}
/// Look up a currency by its ISO numeric code, e.g. `840`.
pub fn from_numeric_code(code: u32) -> Option<Currency> {{
match code {{
{numeric_arms} _ => None,
}}
}}
}}
"
);
let out_dir = env::var("OUT_DIR").unwrap();
fs::write(Path::new(&out_dir).join("iso_currencies.rs"), code).unwrap();
}