use std::borrow::Cow;
use std::path::Path;
use std::sync::Once;
use std::{fs, panic};
use nanoserde::DeJson;
use crate::{GodotVersion, LATEST_API_VERSION, StopWatch, env_var_or_deprecated};
#[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_gdextension_interface_json(watch: &mut StopWatch) -> Cow<'static, str> {
println!("cargo:rerun-if-env-changed=GDRUST_GODOT_INTERFACE_JSON");
watch.record("load_interface_json");
if let Ok(path) = std::env::var("GDRUST_GODOT_INTERFACE_JSON")
&& let Ok(contents) = fs::read_to_string(&path)
{
Cow::Owned(contents)
} else {
gdextension_api::load_gdextension_interface_json()
}
}
pub fn load_custom_extension_api_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_extension_api_json())
.expect("failed to deserialize JSON");
let json_header_version = extension_api
.header
.into_godot_version()
.validate_or_panic();
if json_header_version.is_newer_than_latest()
&& std::env::var("GDRUST_GODOT_INTERFACE_JSON").is_err()
{
let (major, minor, patch) = LATEST_API_VERSION;
println!(
"cargo::warning=Using Godot version API {h_version} specified in `GDRUST_GODOT_API_JSON` with \
prebuilt Godot headers {major}.{minor}.{patch}.\
Consider providing custom `gdextension_interface.json` with `GDRUST_GODOT_INTERFACE_JSON` env variable instead.",
h_version = json_header_version.full_string,
);
}
json_header_version
}