use anyhow::{Context, Result};
use std::fmt::Write as FmtWrite;
use std::fs;
use std::path::Path;
fn parse_csv_rows(path: &Path) -> Result<Vec<Vec<String>>> {
let csv = fs::read_to_string(path).with_context(|| format!("reading {}", path.display()))?;
let mut rows = Vec::new();
for (i, line) in csv.lines().enumerate() {
if i == 0 {
continue; }
let line = line.trim();
if line.is_empty() {
continue;
}
let cols: Vec<String> = line.split(',').map(|s| s.trim().to_string()).collect();
rows.push(cols);
}
Ok(rows)
}
pub(crate) fn run_regen(raw_dir: &Path, out_dir: &Path) -> Result<()> {
let ls_a_path = raw_dir.join("nut00a_ls.csv");
let pl_a_path = raw_dir.join("nut00a_pl.csv");
let ls_b_path = raw_dir.join("nut00b_ls.csv");
for p in [&ls_a_path, &pl_a_path, &ls_b_path] {
println!("cargo:rerun-if-changed={}", p.display());
}
let ls_a = parse_csv_rows(&ls_a_path)?;
let pl_a = parse_csv_rows(&pl_a_path)?;
let ls_b = parse_csv_rows(&ls_b_path)?;
anyhow::ensure!(
ls_a.len() == 678,
"nut00a_ls: expected 678 rows, got {}",
ls_a.len()
);
anyhow::ensure!(
pl_a.len() == 687,
"nut00a_pl: expected 687 rows, got {}",
pl_a.len()
);
anyhow::ensure!(
ls_b.len() == 77,
"nut00b_ls: expected 77 rows, got {}",
ls_b.len()
);
let n_ls_b = ls_b.len();
let mut out = String::new();
writeln!(
out,
"// AUTOGENERATED by siderust-archive build.rs — DO NOT EDIT BY HAND"
)?;
writeln!(
out,
"// Source: src/nutation/raw/nut00a_ls.csv, nut00a_pl.csv, nut00b_ls.csv"
)?;
writeln!(out)?;
writeln!(out, "/// IAU 2000A luni-solar nutation series (678 terms).")?;
writeln!(
out,
"/// Columns: nl, nlp, nf, nd, nom, sp, spt, cp, ce, cet, se"
)?;
writeln!(out, "#[rustfmt::skip]")?;
writeln!(out, "pub static NUT00A_LS: [[f64; 11]; 678] = [")?;
for row in &ls_a {
anyhow::ensure!(row.len() == 11, "nut00a_ls row has {} columns", row.len());
writeln!(out, " [{}],", row.join(", "))?;
}
writeln!(out, "];")?;
writeln!(out)?;
writeln!(out, "/// IAU 2000A planetary nutation series (687 terms).")?;
writeln!(
out,
"/// Columns: nl, nf, nd, nom, nme, nve, nea, nma, nju, nsa, nur, nne, npa, sp, cp, se, ce"
)?;
writeln!(out, "#[rustfmt::skip]")?;
writeln!(out, "pub static NUT00A_PL: [[i32; 17]; 687] = [")?;
for row in &pl_a {
anyhow::ensure!(row.len() == 17, "nut00a_pl row has {} columns", row.len());
writeln!(out, " [{}],", row.join(", "))?;
}
writeln!(out, "];")?;
writeln!(out)?;
writeln!(out, "pub const NUT00B_NTERMS: usize = {n_ls_b};")?;
writeln!(out)?;
writeln!(
out,
"/// IAU 2000B luni-solar nutation series ({n_ls_b} terms)."
)?;
writeln!(
out,
"/// Columns: nl, nlp, nf, nd, nom, sp, spt, cp, ce, cet, se"
)?;
writeln!(out, "#[rustfmt::skip]")?;
writeln!(out, "pub static NUT00B_LS: [[f64; 11]; {n_ls_b}] = [")?;
for row in &ls_b {
anyhow::ensure!(row.len() == 11, "nut00b_ls row has {} columns", row.len());
writeln!(out, " [{}],", row.join(", "))?;
}
writeln!(out, "];")?;
let out_path = out_dir.join("nutation_data.rs");
fs::write(&out_path, &out).with_context(|| format!("writing {}", out_path.display()))?;
Ok(())
}