use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;
fn main() {
let out_dir = env::var("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("hilbert_tables.rs");
let mut f = File::create(&dest_path).unwrap();
generate_hilbert_tables(&mut f).unwrap();
println!("cargo:rerun-if-changed=build.rs");
}
fn generate_hilbert_tables(f: &mut File) -> std::io::Result<()> {
writeln!(f, "// Auto-generated Hilbert curve state tables")?;
writeln!(f, "// DO NOT EDIT - Generated by build.rs\n")?;
writeln!(f, "/// Hilbert curve state transition table")?;
writeln!(f, "/// Maps (state, octant) -> (next_state, hilbert_index)")?;
writeln!(f, "pub const HILBERT_STATE_TABLE: [[(u8, u8); 8]; 24] = [")?;
let state_table = generate_proper_state_table();
for (_state, state_row) in state_table.iter().enumerate().take(24) {
write!(f, " [")?;
for (octant, &(next_state, hilbert_idx)) in state_row.iter().enumerate() {
write!(f, "({}, {})", next_state, hilbert_idx)?;
if octant < 7 {
write!(f, ", ")?;
}
}
writeln!(f, "],")?;
}
writeln!(f, "];\n")?;
writeln!(f, "/// Binary to Gray code conversion")?;
writeln!(f, "pub const BINARY_TO_GRAY: [u8; 8] = [")?;
for i in 0..8 {
let gray = i ^ (i >> 1);
write!(f, "{}", gray)?;
if i < 7 {
write!(f, ", ")?;
}
}
writeln!(f, "];\n")?;
writeln!(f, "/// Gray to binary code conversion")?;
writeln!(f, "pub const GRAY_TO_BINARY: [u8; 8] = [")?;
for gray in 0..8 {
let binary = gray_to_binary(gray);
write!(f, "{}", binary)?;
if gray < 7 {
write!(f, ", ")?;
}
}
writeln!(f, "];\n")?;
Ok(())
}
fn generate_proper_state_table() -> Vec<Vec<(u8, u8)>> {
let mut table = vec![vec![(0u8, 0u8); 8]; 24];
table[0] = vec![
(1, 0), (0, 1), (0, 3), (2, 2), (8, 7), (0, 6), (0, 4), (3, 5), ];
#[allow(clippy::needless_range_loop)]
for state in 1..24 {
for octant in 0..8 {
let _transformed = transform_octant(state, octant);
let base_next = table[0][octant].0;
let base_idx = table[0][octant].1;
let next_state = (base_next + state as u8) % 24;
let hilbert_idx = transform_index(state, base_idx);
table[state][octant] = (next_state, hilbert_idx);
}
}
table
}
fn transform_octant(state: usize, octant: usize) -> usize {
let rotation = state % 6;
let reflection = state / 6;
let mut x = octant & 1;
let mut y = (octant >> 1) & 1;
let mut z = (octant >> 2) & 1;
match rotation {
1 => {
let t = x;
x = y;
y = z;
z = t;
}
2 => {
let t = x;
x = z;
z = y;
y = t;
}
3 => std::mem::swap(&mut y, &mut z),
4 => std::mem::swap(&mut x, &mut z),
5 => std::mem::swap(&mut x, &mut y),
_ => {}
}
if reflection & 1 != 0 {
x ^= 1;
}
if reflection & 2 != 0 {
y ^= 1;
}
(z << 2) | (y << 1) | x
}
fn transform_index(state: usize, index: u8) -> u8 {
transform_octant(state, index as usize) as u8
}
fn gray_to_binary(gray: u8) -> u8 {
let mut binary = gray;
let mut mask = gray >> 1;
while mask != 0 {
binary ^= mask;
mask >>= 1;
}
binary
}