#![allow(dead_code, clippy::question_mark)]
use nanoserde::DeJson;
#[derive(DeJson)]
pub struct HeaderJson {
pub _copyright: Vec<String>,
#[nserde(rename = "$schema")]
#[expect(dead_code)]
pub schema: String,
pub format_version: u32,
pub types: Vec<HeaderType>,
pub interface: Vec<HeaderInterfaceFunction>,
}
#[derive(DeJson)]
pub struct HeaderType {
pub name: String,
pub kind: String,
pub description: Option<Vec<String>>,
pub deprecated: Option<HeaderDeprecated>,
pub is_bitfield: Option<bool>,
pub values: Option<Vec<HeaderEnumValue>>,
pub parent: Option<String>,
pub is_const: Option<bool>,
pub is_uninitialized: Option<bool>,
#[nserde(rename = "type")]
pub type_: Option<String>,
pub members: Option<Vec<HeaderStructMember>>,
pub return_value: Option<HeaderReturnValue>,
pub arguments: Option<Vec<HeaderArgument>>,
}
#[derive(DeJson, Clone)]
pub struct HeaderEnumValue {
pub name: String,
pub value: i64,
pub description: Option<Vec<String>>,
}
#[derive(DeJson)]
pub struct HeaderStructMember {
pub name: String,
#[nserde(rename = "type")]
pub type_: String,
pub description: Option<Vec<String>>,
}
#[derive(DeJson, Clone)]
pub struct HeaderReturnValue {
#[nserde(rename = "type")]
pub type_: String,
pub description: Option<Vec<String>>,
}
#[derive(DeJson, Clone)]
pub struct HeaderArgument {
#[nserde(rename = "type")]
pub type_: String,
pub name: Option<String>,
pub description: Option<Vec<String>>,
}
#[derive(DeJson)]
pub struct HeaderInterfaceFunction {
pub name: String,
pub return_value: Option<HeaderReturnValue>,
pub arguments: Vec<HeaderArgument>,
pub description: Vec<String>,
pub since: String,
pub deprecated: Option<HeaderDeprecated>,
pub see: Option<Vec<String>>,
pub legacy_type_name: Option<String>,
}
#[derive(DeJson)]
pub struct HeaderDeprecated {
pub since: String,
pub message: Option<String>,
pub replace_with: Option<String>,
}
#[cfg(test)] #[cfg_attr(published_docs, doc(cfg(test)))]
mod tests {
use super::*;
fn find_named<'a, T>(items: &'a [T], name: &str, get_name: impl Fn(&T) -> &str) -> &'a T {
items
.iter()
.find(|item| get_name(item) == name)
.unwrap_or_else(|| panic!("{name} not found"))
}
#[test]
fn test_parse_header_json() {
let mut watch = godot_bindings::StopWatch::start();
let json_str = godot_bindings::load_gdextension_interface_json(&mut watch);
let model: HeaderJson =
DeJson::deserialize_json(json_str.as_ref()).expect("failed to deserialize JSON");
assert_eq!(model.format_version, 1);
let variant_type = find_named(&model.types, "GDExtensionVariantType", |t| &t.name);
assert_eq!(variant_type.kind, "enum");
assert!(variant_type.values.is_some());
let call_error = find_named(&model.types, "GDExtensionCallError", |t| &t.name);
assert_eq!(call_error.kind, "struct");
assert!(call_error.members.is_some());
let mem_alloc = find_named(&model.interface, "mem_alloc", |f| &f.name);
assert_eq!(mem_alloc.since, "4.1");
}
}