Skip to content

Commit 5245044

Browse files
committed
Virtual methods: selectively inherit/override/remove optional/required-ness from base
1 parent faa2bb9 commit 5245044

File tree

3 files changed

+41
-15
lines changed

3 files changed

+41
-15
lines changed

godot-codegen/src/generator/virtual_traits.rs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use crate::generator::functions_common::FnCode;
99
use crate::generator::{docs, functions_common};
1010
use crate::models::domain::{
11-
ApiView, Class, ClassLike, ClassMethod, FnQualifier, Function, TyName,
11+
ApiView, Class, ClassLike, ClassMethod, FnQualifier, Function, TyName, VirtualMethodPresence,
1212
};
1313
use crate::special_cases;
1414
use crate::util::ident;
@@ -153,12 +153,20 @@ fn make_special_virtual_methods(notification_enum_name: &Ident) -> TokenStream {
153153

154154
fn make_virtual_method(
155155
method: &ClassMethod,
156-
override_is_required: Option<bool>,
156+
presence: VirtualMethodPresence,
157157
) -> Option<TokenStream> {
158158
if !method.is_virtual() {
159159
return None;
160160
}
161161

162+
// Possibly change behavior of required/optional-ness of the virtual method in derived classes.
163+
// It's also possible that it's removed, which would not declare it at all in the `I*` trait.
164+
let is_virtual_required = match presence {
165+
VirtualMethodPresence::Inherit => method.is_virtual_required(),
166+
VirtualMethodPresence::Override { is_required } => is_required,
167+
VirtualMethodPresence::Remove => return None,
168+
};
169+
162170
// Virtual methods are never static.
163171
let qualifier = method.qualifier();
164172
assert!(matches!(qualifier, FnQualifier::Mut | FnQualifier::Const));
@@ -170,8 +178,7 @@ fn make_virtual_method(
170178
// make_return() requests following args, but they are not used for virtual methods. We can provide empty streams.
171179
varcall_invocation: TokenStream::new(),
172180
ptrcall_invocation: TokenStream::new(),
173-
is_virtual_required: override_is_required
174-
.unwrap_or_else(|| method.is_virtual_required()),
181+
is_virtual_required,
175182
is_varcall_fallible: true,
176183
},
177184
None,
@@ -191,7 +198,7 @@ fn make_all_virtual_methods(
191198

192199
for method in class.methods.iter() {
193200
// Assumes that inner function filters on is_virtual.
194-
if let Some(tokens) = make_virtual_method(method, None) {
201+
if let Some(tokens) = make_virtual_method(method, VirtualMethodPresence::Inherit) {
195202
all_tokens.push(tokens);
196203
}
197204
}
@@ -201,14 +208,17 @@ fn make_all_virtual_methods(
201208
for method in base_class.methods.iter() {
202209
// Certain derived classes in Godot implement a virtual method declared in a base class, thus no longer
203210
// making it required. This isn't advertised in the extension_api, but instead manually tracked via special cases.
204-
let is_required =
205-
special_cases::is_derived_virtual_method_required(class.name(), method.name());
211+
let derived_presence =
212+
special_cases::get_derived_virtual_method_presence(class.name(), method.name());
206213

207-
if let Some(tokens) = make_virtual_method(method, is_required) {
214+
if let Some(tokens) = make_virtual_method(method, derived_presence) {
208215
all_tokens.push(tokens);
209216
}
210217
}
211218
}
212219

213220
all_tokens
214221
}
222+
223+
// ----------------------------------------------------------------------------------------------------------------------------------------------
224+
// Helper types

godot-codegen/src/models/domain.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,20 @@ pub enum ArgPassing {
723723

724724
// ----------------------------------------------------------------------------------------------------------------------------------------------
725725

726+
/// Behavior of virtual methods in derived classes.
727+
pub enum VirtualMethodPresence {
728+
/// Preserve default behavior of base class (required or optional).
729+
Inherit,
730+
731+
/// Virtual method is now required/optional according to `is_required`, independent of base method declaration.
732+
Override { is_required: bool },
733+
734+
/// Virtual method is removed in derived classes (no longer appearing in their interface trait).
735+
Remove,
736+
}
737+
738+
// ----------------------------------------------------------------------------------------------------------------------------------------------
739+
726740
/// Contains multiple naming conventions for types (classes, builtin classes, enums).
727741
#[derive(Clone, Eq, PartialEq, Hash)]
728742
pub struct TyName {

godot-codegen/src/special_cases/special_cases.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
#![allow(clippy::match_like_matches_macro)] // if there is only one rule
2727

2828
use crate::conv::to_enum_type_uncached;
29-
use crate::models::domain::{Enum, RustTy, TyName};
29+
use crate::models::domain::{Enum, RustTy, TyName, VirtualMethodPresence};
3030
use crate::models::json::{JsonBuiltinMethod, JsonClassMethod, JsonSignal, JsonUtilityFunction};
3131
use crate::special_cases::codegen_special_cases;
3232
use crate::util::option_as_slice;
@@ -847,12 +847,14 @@ pub fn is_virtual_method_required(class_name: &TyName, rust_method_name: &str) -
847847

848848
// Adjustments for Godot 4.4+, where a virtual method is no longer needed (e.g. in a derived class).
849849
#[rustfmt::skip]
850-
pub fn is_derived_virtual_method_required(class_name: &TyName, rust_method_name: &str) -> Option<bool> {
851-
match (class_name.godot_ty.as_str(), rust_method_name) {
852-
// Required in base class, no longer in derived; https://github.com/godot-rust/gdext/issues/1133.
853-
| ("AudioStreamPlaybackResampled", "mix")
854-
855-
=> Some(false), _ => None
850+
pub fn get_derived_virtual_method_presence(class_name: &TyName, rust_method_name: &str) -> VirtualMethodPresence {
851+
match (class_name.godot_ty.as_str(), rust_method_name) {
852+
// Required in base class, no longer in derived; https://github.com/godot-rust/gdext/issues/1133.
853+
| ("AudioStreamPlaybackResampled", "mix")
854+
=> VirtualMethodPresence::Remove,
855+
856+
// Default: inherit presence from base class.
857+
_ => VirtualMethodPresence::Inherit,
856858
}
857859
}
858860

0 commit comments

Comments
 (0)