use std::fs;
use std::path::Path;
use std::sync::Once;
use nanoserde::DeJson;
use crate::depend_on_custom_json::header_gen::generate_rust_binding;
use crate::godot_version::validate_godot_version;
use crate::{GodotVersion, StopWatch, env_var_or_deprecated};
#[rustfmt::skip] use gdextension_api::version_4_6::load_gdextension_header_h as load_latest_gdextension_headers;
#[derive(DeJson)]
struct JsonExtensionApi {
pub header: JsonHeader,
}
#[derive(DeJson)]
struct JsonHeader {
pub version_major: u8,
pub version_minor: u8,
pub version_patch: u8,
pub version_status: String,
pub version_build: String,
pub version_full_name: String,
}
impl JsonHeader {
fn into_godot_version(self) -> GodotVersion {
GodotVersion {
full_string: self.version_full_name,
major: self.version_major,
minor: self.version_minor,
patch: self.version_patch,
status: self.version_status,
custom_rev: Some(self.version_build),
}
}
}
pub fn load_custom_gdextension_json() -> String {
static WARN_ONCE: Once = Once::new();
let env_var = env_var_or_deprecated(
&WARN_ONCE,
"GDRUST_GODOT_API_JSON",
"GODOT4_GDEXTENSION_JSON",
);
println!("cargo:rerun-if-env-changed=GDRUST_GODOT_API_JSON");
println!("cargo:rerun-if-env-changed=GODOT4_GDEXTENSION_JSON");
let path = env_var.expect(
"godot-rust with `api-custom-json` feature requires GDRUST_GODOT_API_JSON \
environment variable (with the path to the said json).",
);
let json_path = Path::new(&path);
fs::read_to_string(json_path).unwrap_or_else(|_| {
panic!(
"failed to open file with custom GDExtension JSON {}.",
json_path.display()
)
})
}
pub(crate) fn read_godot_version() -> GodotVersion {
let extension_api: JsonExtensionApi = DeJson::deserialize_json(&load_custom_gdextension_json())
.expect("failed to deserialize JSON");
let version = extension_api.header.into_godot_version();
validate_godot_version(&version);
version
}
pub(crate) fn write_gdextension_headers(
out_h_path: &Path,
out_rs_path: &Path,
watch: &mut StopWatch,
) {
let h_contents = load_latest_gdextension_headers();
fs::write(out_h_path, h_contents.as_ref())
.unwrap_or_else(|e| panic!("failed to write gdextension_interface.h: {e}"));
watch.record("write_header_h");
generate_rust_binding(out_h_path, out_rs_path);
watch.record("generate_header_rs");
}