use anyhow::{Context, Result};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use std::collections::HashSet;
use std::env;
use std::fs;
use std::path::Path;
fn main() -> Result<()> {
let words_dir = Path::new("words");
let out_dir = env::var_os("OUT_DIR").context("OUT_DIR not set")?;
let dest_path = Path::new(&out_dir).join("words.rs");
let list_sizes = ["small", "medium", "large"];
let list_names = ["adjectives", "adverbs", "nouns"];
let list_modules = list_sizes
.into_iter()
.map(|list_size| {
let lists = list_names
.into_iter()
.map(|list_name| {
let words_path = words_dir.join(list_size).join(list_name).with_extension("txt");
println!("cargo:rerun-if-changed={}", words_path.to_string_lossy());
let words_raw = fs::read_to_string(&words_path)
.with_context(|| format!("Could not read word list from {words_path:?}"))?;
let words = split_words_deduplicate_and_sort(&words_raw);
let list_ident = format_ident!("{}", list_name.to_uppercase());
let list_len = words.len();
let list = quote! { pub static #list_ident: [&str; #list_len] = [ #( #words ),* ]; };
Ok(list)
})
.collect::<Result<Vec<TokenStream>>>()?;
let module_ident = format_ident!("{}", list_size);
let module_tokens = quote! { pub mod #module_ident { #(#lists)* } };
Ok(module_tokens)
})
.collect::<Result<Vec<TokenStream>>>()?;
let modules = quote! { #(#list_modules)* };
let module = modules.to_string();
fs::write(&dest_path, module)
.with_context(|| format!("Could not write word lists to output file {dest_path:?}"))?;
println!("cargo:rerun-if-changed=build.rs");
Ok(())
}
fn split_words_deduplicate_and_sort(input: &str) -> Vec<&str> {
let words = input.split_whitespace().collect::<HashSet<_>>();
let mut words = words.into_iter().collect::<Vec<_>>();
words.sort();
words
}