use std::path::PathBuf;
const LETTERS: [char; 9] = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'];
const MAX_DELTA_N: u8 = 2;
fn main() {
let delta_n_types = generate_delta_n_types();
let out_dir = std::env::var("OUT_DIR").unwrap();
std::fs::write(
PathBuf::from(out_dir).join("delta_n_types.rs"),
delta_n_types,
)
.unwrap();
}
fn generate_delta_n_types() -> String {
let mut all_types = "".to_string();
for field_count in 2..=MAX_DELTA_N {
let bool_combinations = make_bool_combinations(field_count as _);
let mut change_combinations = "".to_string();
let diff_n_generics: String = LETTERS[0..field_count as usize]
.iter()
.map(|l| format!("{},", l))
.collect();
for bools in bool_combinations {
let mut change_str = "Change".to_string();
let mut changed_generics = "".to_string();
bools
.iter()
.enumerate()
.filter(|(_, changed)| **changed)
.for_each(|(idx, _)| {
change_str += &format!("_{}", idx);
changed_generics += &format!("{}, ", LETTERS[idx]);
});
if &change_str == "Change" {
continue;
}
change_combinations += &format!(
r#"{change_str}({changed_generics}),
"#,
change_str = change_str,
changed_generics = changed_generics
);
}
let diff_n = format!(
r#"
#[derive(serde::Serialize)]
#[cfg_attr(any(test, feature = "impl-tester"), derive(Debug, PartialEq))]
#[allow(non_camel_case_types, missing_docs)]
pub enum Delta{field_count}<{diff_n_generics}> {{
NoChange,
{change_combinations}
}}"#,
field_count = field_count,
change_combinations = change_combinations,
diff_n_generics = diff_n_generics,
);
let diff_n_owned = format!(
r#"
#[derive(serde::Deserialize)]
#[allow(non_camel_case_types, missing_docs)]
pub enum DeltaOwned{field_count}<{diff_n_generics}> {{
NoChange,
{change_combinations}
}}"#,
field_count = field_count,
change_combinations = change_combinations,
diff_n_generics = diff_n_generics,
);
all_types += &diff_n;
all_types += &diff_n_owned;
}
all_types
}
fn make_bool_combinations(field_count: usize) -> Vec<Vec<bool>> {
let mut all = vec![];
let start = vec![false; field_count];
bool_combinations_recursive(&mut all, 0, field_count, start);
all
}
fn bool_combinations_recursive(
all: &mut Vec<Vec<bool>>,
start_idx: usize,
field_count: usize,
current: Vec<bool>,
) {
if start_idx > field_count {
return;
}
all.push(current.clone());
for idx in start_idx..field_count {
let mut flipped = current.clone();
flipped[idx] = !flipped[idx];
bool_combinations_recursive(all, idx + 1, field_count, flipped);
}
}