use std::fs::{self, File};
use std::io::Write;
use std::path::Path;
use serde_json::Value;
fn main() {
if std::env::var("DOCS_RS").is_ok() {
return;
}
println!("cargo:rerun-if-changed=src/jsons/Civ V - Gods & Kings/TerrainTypes.json");
println!("cargo:rerun-if-changed=src/jsons/Civ V - Gods & Kings/BaseTerrains.json");
println!("cargo:rerun-if-changed=src/jsons/Civ V - Gods & Kings/Features.json");
println!("cargo:rerun-if-changed=src/jsons/Civ V - Gods & Kings/NaturalWonders.json");
println!("cargo:rerun-if-changed=src/jsons/Civ V - Gods & Kings/TileResources.json");
println!("cargo:rerun-if-changed=src/jsons/Civ V - Gods & Kings/Nations.json");
let json_path = Path::new(env!("CARGO_MANIFEST_DIR"))
.join("src")
.join("jsons")
.join("Civ V - Gods & Kings");
let tile_component_path = Path::new("src/tile_component");
create_enum_from_json(
json_path.join("TerrainTypes.json").to_str().unwrap(),
tile_component_path
.join("terrain_type.rs")
.to_str()
.unwrap(),
"TerrainType",
);
create_enum_from_json(
json_path.join("BaseTerrains.json").to_str().unwrap(),
tile_component_path
.join("base_terrain.rs")
.to_str()
.unwrap(),
"BaseTerrain",
);
create_enum_from_json(
json_path.join("Features.json").to_str().unwrap(),
tile_component_path.join("feature.rs").to_str().unwrap(),
"Feature",
);
create_enum_from_json(
json_path.join("NaturalWonders.json").to_str().unwrap(),
tile_component_path
.join("natural_wonder.rs")
.to_str()
.unwrap(),
"NaturalWonder",
);
create_enum_from_json(
json_path.join("Resources.json").to_str().unwrap(),
tile_component_path.join("resource.rs").to_str().unwrap(),
"Resource",
);
create_enum_from_json(
json_path.join("Nations.json").to_str().unwrap(),
Path::new("src/nation.rs").to_str().unwrap(),
"Nation",
);
}
fn create_enum_from_json(json_path: &str, dest_path: &str, enum_name: &str) {
let json_string_without_comment = load_json_file_and_strip_json_comments(json_path);
let value_list: Vec<Value> = serde_json::from_str(&json_string_without_comment)
.unwrap_or_else(|_| panic!("{}'{}'", "Can't serde ", json_path));
let names: Vec<&str> = value_list
.iter()
.map(|terrain| terrain.get("name").and_then(|v| v.as_str()).unwrap_or(""))
.collect();
let mut output = String::new();
output.push_str("// Auto-generated by build.rs, DO NOT EDIT\n");
output.push_str("use enum_map::Enum;\n");
output.push_str("use serde::{Deserialize, Serialize};\n");
output.push('\n');
output.push_str(
"#[derive(Enum, PartialEq, Eq, Clone, Copy, Hash, Serialize, Deserialize, Debug)]\n",
);
output.push_str(&format!("pub enum {} {{\n", enum_name));
let enum_variants: Vec<String> = names
.iter()
.map(|name| {
let variant: String = name
.split_whitespace()
.map(|word| {
let mut chars = word.chars();
match chars.next() {
Some(c) => c.to_uppercase().chain(chars).collect(),
None => String::new(),
}
})
.collect::<Vec<String>>()
.join("")
.chars()
.filter(|c| c.is_ascii_alphabetic())
.collect();
variant
})
.collect();
for variant in enum_variants.iter() {
output.push_str(&format!(" {},\n", variant));
}
output.push_str("}\n\n");
output.push_str(&format!("impl {} {{\n", enum_name));
output.push_str(" pub fn as_str(&self) -> &'static str {\n");
output.push_str(" match self {\n");
for (variant, name) in enum_variants.iter().zip(names.iter()) {
output.push_str(&format!(
" {}::{} => \"{}\",\n",
enum_name, variant, name
));
}
output.push_str(" }\n");
output.push_str(" }\n");
output.push_str("}\n");
let mut file = File::create(dest_path).expect("Could not create output file");
file.write_all(output.as_bytes())
.expect("Could not write to file");
}
fn load_json_file_and_strip_json_comments(path: &str) -> String {
let json_string_with_comment = fs::read_to_string(path).unwrap();
strip_json_comments(&json_string_with_comment, true)
}
pub fn strip_json_comments(json_with_comments: &str, preserve_locations: bool) -> String {
let mut json_without_comments = String::new();
let mut block_comment_depth: u8 = 0;
let mut is_in_string: bool = false;
for line in json_with_comments.split('\n') {
let mut last_char: Option<char> = None;
for cur_char in line.chars() {
if block_comment_depth == 0 && last_char != Some('\\') && cur_char == '"' {
is_in_string = !is_in_string;
}
if !is_in_string && last_char == Some('/') && cur_char == '/' {
last_char = None;
if preserve_locations {
json_without_comments.push_str(" ");
}
break; }
if !is_in_string && last_char == Some('/') && cur_char == '*' {
block_comment_depth += 1;
last_char = None;
if preserve_locations {
json_without_comments.push_str(" ");
}
} else if !is_in_string && last_char == Some('*') && cur_char == '/' {
if block_comment_depth > 0 {
block_comment_depth = block_comment_depth.saturating_sub(1);
}
last_char = None;
if preserve_locations {
json_without_comments.push_str(" ");
}
} else {
if block_comment_depth != 0 {
if preserve_locations {
json_without_comments.push(' ');
}
} else if let Some(last_char) = last_char {
json_without_comments.push(last_char);
}
last_char = Some(cur_char);
}
}
if let Some(last_char) = last_char {
if block_comment_depth == 0 {
json_without_comments.push(last_char);
} else if preserve_locations {
json_without_comments.push(' ');
}
}
while json_without_comments.ends_with(' ') {
json_without_comments.pop();
}
json_without_comments.push('\n');
}
json_without_comments
}