From 4f2a14e0869517b767e6c26e4897646b57bd480a Mon Sep 17 00:00:00 2001 From: Seth Carter Date: Tue, 9 Jun 2026 15:12:57 +0100 Subject: [PATCH] Implement the Default trait with more specific code than the derived Default, for DuplicateFlags. --- godot-codegen/src/generator/enums.rs | 13 ++++++++++++ godot-codegen/src/models/domain/enums.rs | 3 ++- godot-codegen/src/models/domain_mapping.rs | 3 +++ .../src/special_cases/special_cases.rs | 21 +++++++++++++++++++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/godot-codegen/src/generator/enums.rs b/godot-codegen/src/generator/enums.rs index 2238de5da..6e004470e 100644 --- a/godot-codegen/src/generator/enums.rs +++ b/godot-codegen/src/generator/enums.rs @@ -115,6 +115,18 @@ pub fn make_enum_definition_with( let index_enum_impl = make_enum_index_impl(enum_); let bitwise_impls = make_enum_bitwise_operators(enum_, enum_bitmask.as_ref()); + let special_default_impl = if let Some(override_default) = enum_.override_default.as_ref() { + quote! { + impl Default for #name { + fn default() -> Self { + #override_default + } + } + } + } else { + TokenStream::new() + }; + let var_trait_set = if enum_.is_exhaustive { quote! { fn var_set(field: &mut Self, value: Self::Via) { @@ -144,6 +156,7 @@ pub fn make_enum_definition_with( #engine_trait_impl #index_enum_impl #bitwise_impls + #special_default_impl impl crate::meta::GodotConvert for #name { type Via = #ord_type; diff --git a/godot-codegen/src/models/domain/enums.rs b/godot-codegen/src/models/domain/enums.rs index 58b4b1a6d..9a155ecf9 100644 --- a/godot-codegen/src/models/domain/enums.rs +++ b/godot-codegen/src/models/domain/enums.rs @@ -20,6 +20,7 @@ pub struct Enum { pub godot_name: String, pub surrounding_class: Option, pub is_bitfield: bool, + pub override_default: Option, pub is_private: bool, pub is_exhaustive: bool, pub enumerators: Vec, @@ -33,7 +34,7 @@ impl Enum { // Debug is implemented manually, using enumerator name. This can be derived once we use proper enums. let mut derives = vec!["Copy", "Clone", "Eq", "PartialEq", "Hash"]; - if self.is_bitfield { + if self.is_bitfield && self.override_default.is_none() { derives.push("Default"); } diff --git a/godot-codegen/src/models/domain_mapping.rs b/godot-codegen/src/models/domain_mapping.rs index 5b1d843bc..9908bcaee 100644 --- a/godot-codegen/src/models/domain_mapping.rs +++ b/godot-codegen/src/models/domain_mapping.rs @@ -766,6 +766,8 @@ impl Enum { .unwrap_or(json_is_bitfield); let is_private = special_cases::is_enum_private(surrounding_class, &godot_name); let is_exhaustive = special_cases::is_enum_exhaustive(surrounding_class, &godot_name); + let override_default = + special_cases::does_enum_have_special_default(surrounding_class, &godot_name); let rust_enum_name = conv::make_enum_name_str(&godot_name); let rust_enumerator_names = { @@ -800,6 +802,7 @@ impl Enum { godot_name, surrounding_class: surrounding_class.cloned(), is_bitfield, + override_default, is_private, is_exhaustive, enumerators, diff --git a/godot-codegen/src/special_cases/special_cases.rs b/godot-codegen/src/special_cases/special_cases.rs index 36a019a96..d6b7fea20 100644 --- a/godot-codegen/src/special_cases/special_cases.rs +++ b/godot-codegen/src/special_cases/special_cases.rs @@ -1361,6 +1361,27 @@ pub fn is_enum_bitfield(class_name: Option<&TyName>, enum_name: &str) -> Option< } } +/// For types where a [`Default`](Default) is helpful, but the default value should +/// be something other than what would be returned by a `#[derive(Default)]` implementation. +/// +/// An example of this is `DuplicateFlags`, where the default flags to `duplicate` are non-zero, +/// so if one wants to use "all flags except one" in `duplicate_ex`, the most natural way to do +/// so would be to pass `DuplicateFlags::default() & !DuplicateFlags::USE_INSTATANTIATION` to `flags`. +/// +/// * `Some(TokenStream)` -> function body which will be psted into the `Default::default` implementation. +/// * `None` -> no special default, i.e. if a Default is generated it will be with an automatic derive. +#[rustfmt::skip] +pub fn does_enum_have_special_default(class_name: Option<&TyName>, enum_name: &str) -> Option { + let class_name = class_name.map(|c| c.godot_ty.as_str()); + match (class_name, enum_name) { + (Some("Node"), "DuplicateFlags") => Some(quote! { + Self::SIGNALS | Self::GROUPS | Self::SCRIPTS | Self::USE_INSTANTIATION + }), + + _ => None + } +} + /// Whether an enum can be combined with another enum (return value) for bitmasking purposes. /// /// If multiple masks are ever necessary, this can be extended to return a slice instead of Option.