Skip to content

Commit 2f761d4

Browse files
committed
Handle @export_file on arrays only available in Godot 4.3+
Also adjust error when #[export(file)] is used on arrays in older versions
1 parent 090843d commit 2f761d4

File tree

4 files changed

+90
-50
lines changed

4 files changed

+90
-50
lines changed

godot-bindings/src/lib.rs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -217,20 +217,16 @@ pub fn remove_dir_all_reliable(path: &Path) {
217217
}
218218
}
219219

220-
// Duplicates code from `make_gdext_build_struct` in `godot-codegen/generator/gdext_build_struct.rs`.
220+
/// Concrete check against an API level, not runtime level.
221+
///
222+
/// Necessary in `build.rs`, which doesn't itself have the cfgs.
221223
pub fn before_api(major_minor: &str) -> bool {
222-
let mut parts = major_minor.split('.');
223-
let queried_major = parts
224-
.next()
225-
.unwrap()
226-
.parse::<u8>()
227-
.expect("invalid major version");
228-
let queried_minor = parts
229-
.next()
230-
.unwrap()
231-
.parse::<u8>()
232-
.expect("invalid minor version");
233-
assert_eq!(queried_major, 4, "major version must be 4");
224+
let queried_minor = major_minor
225+
.strip_prefix("4.")
226+
.expect("major version must be 4");
227+
228+
let queried_minor = queried_minor.parse::<u8>().expect("invalid minor version");
229+
234230
let godot_version = get_godot_version();
235231
godot_version.minor < queried_minor
236232
}

godot-core/src/registry/property.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,9 @@ pub mod export_info_functions {
449449

450450
// Array<GString> or PackedStringArray field:
451451
// { "type": 28, "hint": 23, "hint_string": "4/13:*.png" }
452+
#[cfg(since_api = "4.3")]
452453
VariantType::PACKED_STRING_ARRAY => to_string_array_hint(hint, filter),
454+
#[cfg(since_api = "4.3")]
453455
VariantType::ARRAY if field_ty.is_array_of_elem::<GString>() => {
454456
to_string_array_hint(hint, filter)
455457
}
@@ -460,10 +462,17 @@ pub mod export_info_functions {
460462

461463
// TODO nicer error handling.
462464
// Compile time may be difficult (at least without extra traits... maybe const fn?). But at least more context info, field name etc.
465+
#[cfg(since_api = "4.3")]
463466
panic!(
464467
"#[export({attribute_name})] only supports GString, Array<String> or PackedStringArray field types\n\
465468
encountered: {field_ty:?}"
466469
);
470+
471+
#[cfg(before_api = "4.3")]
472+
panic!(
473+
"#[export({attribute_name})] only supports GString type prior to Godot 4.3\n\
474+
encountered: {field_ty:?}"
475+
);
467476
}
468477
}
469478
}

itest/rust/build.rs

Lines changed: 62 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ fn collect_inputs() -> Vec<Input> {
150150
push!(inputs; PackedStringArray, PackedStringArray, PackedStringArray(), PackedStringArray::new());
151151
push!(inputs; PackedVector2Array, PackedVector2Array, PackedVector2Array(), PackedVector2Array::new());
152152
push!(inputs; PackedVector3Array, PackedVector3Array, PackedVector3Array(), PackedVector3Array::new());
153+
153154
// This is being run in a build script at the same time as other build-scripts, so the `rustc-cfg` directives haven't been run for this
154155
// build-script. This means that `#[cfg(since_api = "4.3")]` wouldn't do anything.
155156
if godot_bindings::since_api("4.3") {
@@ -214,6 +215,7 @@ fn main() {
214215
rust: rust_property_tests,
215216
gdscript: gdscript_property_tests,
216217
} = generate_property_template(&inputs);
218+
217219
let extras = inputs.iter().map(|input| &input.extra);
218220

219221
let rust_tokens = quote::quote! {
@@ -465,49 +467,63 @@ fn generate_property_template(inputs: &[Input]) -> PropertyTests {
465467
}
466468
}
467469

468-
let rust = quote! {
469-
#[derive(GodotClass)]
470-
#[class(base = Node, init)]
471-
pub struct PropertyTestsRust {
472-
#(#rust,)*
473-
474-
// All the @export_file/dir variants, with GString, Array<GString> and PackedStringArray.
475-
#[export(file)]
476-
export_file: GString,
470+
// Only available in Godot 4.3+.
471+
let rust_exports_4_3 = if godot_bindings::before_api("4.3") {
472+
TokenStream::new()
473+
} else {
474+
quote! {
477475
#[export(file)]
478476
export_file_array: Array<GString>,
479477
#[export(file)]
480478
export_file_parray: PackedStringArray,
481-
#[export(file = "*.txt")]
482-
export_file_wildcard: GString,
479+
483480
#[export(file = "*.txt")]
484481
export_file_wildcard_array: Array<GString>,
485482
#[export(file = "*.txt")]
486483
export_file_wildcard_parray: PackedStringArray,
487-
#[export(global_file)]
488-
export_global_file: GString,
484+
489485
#[export(global_file)]
490486
export_global_file_array: Array<GString>,
491487
#[export(global_file)]
492488
export_global_file_parray: PackedStringArray,
493-
#[export(global_file = "*.png")]
494-
export_global_file_wildcard: GString,
489+
495490
#[export(global_file = "*.png")]
496491
export_global_file_wildcard_array: Array<GString>,
497492
#[export(global_file = "*.png")]
498493
export_global_file_wildcard_parray: PackedStringArray,
499-
#[export(dir)]
500-
export_dir: GString,
494+
501495
#[export(dir)]
502496
export_dir_array: Array<GString>,
503497
#[export(dir)]
504498
export_dir_parray: PackedStringArray,
505-
#[export(global_dir)]
506-
export_global_dir: GString,
499+
507500
#[export(global_dir)]
508501
export_global_dir_array: Array<GString>,
509502
#[export(global_dir)]
510503
export_global_dir_parray: PackedStringArray,
504+
}
505+
};
506+
507+
let rust = quote! {
508+
#[derive(GodotClass)]
509+
#[class(base = Node, init)]
510+
pub struct PropertyTestsRust {
511+
#(#rust,)*
512+
#rust_exports_4_3
513+
514+
// All the @export_file/dir variants, with GString, Array<GString> and PackedStringArray.
515+
#[export(file)]
516+
export_file: GString,
517+
#[export(file = "*.txt")]
518+
export_file_wildcard: GString,
519+
#[export(global_file)]
520+
export_global_file: GString,
521+
#[export(global_file = "*.png")]
522+
export_global_file_wildcard: GString,
523+
#[export(dir)]
524+
export_dir: GString,
525+
#[export(global_dir)]
526+
export_global_dir: GString,
511527

512528
#[export(multiline)]
513529
export_multiline: GString,
@@ -548,27 +564,16 @@ fn generate_property_template(inputs: &[Input]) -> PropertyTests {
548564
}
549565
};
550566

551-
let gdscript = format!(
552-
r#"
553-
{}
567+
// `extends`, basic `var` and `@export var` declarations
568+
let basic_exports = gdscript.join("\n");
569+
570+
let advanced_exports = r#"
554571
@export_file var export_file: String
555-
@export_file var export_file_array: Array[String]
556-
@export_file var export_file_parray: PackedStringArray
557572
@export_file("*.txt") var export_file_wildcard: String
558-
@export_file("*.txt") var export_file_wildcard_array: Array[String]
559-
@export_file("*.txt") var export_file_wildcard_parray: PackedStringArray
560573
@export_global_file var export_global_file: String
561-
@export_global_file var export_global_file_array: Array[String]
562-
@export_global_file var export_global_file_parray: PackedStringArray
563574
@export_global_file("*.png") var export_global_file_wildcard: String
564-
@export_global_file("*.png") var export_global_file_wildcard_array: Array[String]
565-
@export_global_file("*.png") var export_global_file_wildcard_parray: PackedStringArray
566575
@export_dir var export_dir: String
567-
@export_dir var export_dir_array: Array[String]
568-
@export_dir var export_dir_parray: PackedStringArray
569576
@export_global_dir var export_global_dir: String
570-
@export_global_dir var export_global_dir_array: Array[String]
571-
@export_global_dir var export_global_dir_parray: PackedStringArray
572577
573578
@export_multiline var export_multiline: String
574579
@export_range(0, 20) var export_range_float_0_20: float
@@ -588,9 +593,29 @@ fn generate_property_template(inputs: &[Input]) -> PropertyTests {
588593
@export_enum("Warrior", "Magician", "Thief") var export_enum_int_warrior_magician_thief: int
589594
@export_enum("Slow:30", "Average:60", "VeryFast:200") var export_enum_int_slow_30_average_60_very_fast_200: int
590595
@export_enum("Rebecca", "Mary", "Leah") var export_enum_string_rebecca_mary_leah: String
591-
"#,
592-
gdscript.join("\n")
593-
);
596+
"#;
597+
598+
// Only available in Godot 4.3+.
599+
let advanced_exports_4_3 = r#"
600+
@export_file var export_file_array: Array[String]
601+
@export_file var export_file_parray: PackedStringArray
602+
@export_file("*.txt") var export_file_wildcard_array: Array[String]
603+
@export_file("*.txt") var export_file_wildcard_parray: PackedStringArray
604+
@export_global_file var export_global_file_array: Array[String]
605+
@export_global_file var export_global_file_parray: PackedStringArray
606+
@export_global_file("*.png") var export_global_file_wildcard_array: Array[String]
607+
@export_global_file("*.png") var export_global_file_wildcard_parray: PackedStringArray
608+
@export_dir var export_dir_array: Array[String]
609+
@export_dir var export_dir_parray: PackedStringArray
610+
@export_global_dir var export_global_dir_array: Array[String]
611+
@export_global_dir var export_global_dir_parray: PackedStringArray
612+
"#;
613+
614+
let mut gdscript = format!("{basic_exports}\n{advanced_exports}");
615+
if godot_bindings::since_api("4.3") {
616+
gdscript.push('\n');
617+
gdscript.push_str(advanced_exports_4_3);
618+
}
594619

595620
PropertyTests { rust, gdscript }
596621
}

itest/rust/src/object_tests/property_template_test.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ fn property_template_test(ctx: &TestContext) {
4444
continue;
4545
}
4646

47+
// Skip @export_file and similar properties for Array<GString> and PackedStringArray (only supported in Godot 4.3+).
48+
// Here, we use API and not runtime level, because inclusion/exclusion of GDScript code is determined at build time in godot-bindings.
49+
//
50+
// Name can start in `export_file`, `export_global_file`, `export_dir`, `export_global_dir`.
51+
// Can end in either `_array` or `_parray`.
52+
#[cfg(before_api = "4.3")]
53+
if (name.contains("_file_") || name.contains("_dir_")) && name.ends_with("array") {
54+
continue;
55+
}
56+
4757
if name.starts_with("var_") || name.starts_with("export_") {
4858
properties.insert(name, property);
4959
}

0 commit comments

Comments
 (0)