this_algorithm/words/build.rs
2023-05-12 17:16:55 -04:00

110 lines
3.1 KiB
Rust

#![feature(slice_group_by)]
#![allow(unused_imports)]
use csv::ReaderBuilder;
use serde::{Deserialize, Deserializer, Serialize};
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::{BufRead, BufReader, BufWriter, Write};
use std::path::Path;
fn main() {
let path = Path::new(&env::var("OUT_DIR").unwrap()).join("codegen.rs");
let mut file = BufWriter::new(File::create(path).unwrap());
let wordlist_path = "../wordlist/99-wordlist.csv";
// println!("cargo:rerun-if-changed={}", wordlist_path);
let rdr_builder = ReaderBuilder::new();
// First get the actual wordlist
let words: Vec<Word> = rdr_builder
.from_reader(File::open(wordlist_path).unwrap())
.deserialize()
.collect::<Result<Vec<Word>, _>>()
.unwrap();
// Write it to an array containing all words
write_words(&mut file, &words);
// Make a mapping of all caps word to a reference to the `Word` entry
write_word_map(&mut file, &words);
// Make a mapping of numbers to `Word`s
write_number_to_words(&mut file, &words);
}
fn write_words(mut file: impl Write, words: &[Word]) {
let len = words.len();
writeln!(
&mut file,
r#"/// Static array of `Word`
pub static WORDS: [Word; {len}] = ["#
)
.unwrap();
for result in words.iter() {
writeln!(&mut file, "\t{result:?},").unwrap();
}
writeln!(&mut file, "];\n").unwrap();
}
fn write_word_map(mut file: impl Write, words: &[Word]) {
let mut word_map = phf_codegen::Map::new();
for (idx, word) in words.iter().enumerate() {
let idx_str = format!("&WORDS[{idx}]");
word_map.entry(word.word.to_uppercase(), &idx_str);
}
writeln!(
&mut file,
r#"/// Mapping from all caps `&str` to `&'static Word`
pub static WORD_MAP: phf::Map<&'static str, &Word> = {};"#,
word_map.build()
)
.unwrap();
}
fn write_number_to_words(mut file: impl Write, words: &[Word]) {
let word_number_to_idx = words
.iter()
.enumerate()
.map(|(idx, w)| (w.number, idx))
.collect::<Vec<(u16, usize)>>();
writeln!(
&mut file,
// "pub static NUMBER_TO_WORDS: &[&[usize]] = &["
r#"/// Mapping from each number to its associated word
pub static NUMBER_TO_WORDS: &[&[&Word]] = &["#
)
.unwrap();
for entry in word_number_to_idx
.as_slice()
.group_by(|(number1, _idx1), (number2, _idx2)| number1 == number2)
{
write!(&mut file, "\t&[",).unwrap();
for idx in entry.iter().map(|(_w, idx)| idx) {
// write!(&mut file, "{idx},").unwrap();
write!(&mut file, "&WORDS[{idx}],").unwrap();
}
writeln!(&mut file, "], /* {} */", entry[0].0).unwrap();
}
writeln!(&mut file, "];\n").unwrap();
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Word {
/// The word itself
#[serde(rename = "WORD")]
pub word: String,
/// The binary representation of this number
///
/// The words are responsible for 13 bits of data, so this is fine to fit in a u16
#[serde(rename = "NUMBER")]
pub number: u16,
}