Skip to content

Commit 47bfe89

Browse files
committed
Only provide function name to CallContext in debug
1 parent c4051c0 commit 47bfe89

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+291
-281
lines changed

check.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,9 @@ while [[ $# -gt 0 ]]; do
205205
echo "$HELP_TEXT"
206206
exit 0
207207
;;
208+
--release)
209+
extraCargoArgs+=("--release")
210+
;;
208211
--use-serde)
209212
extraCargoArgs+=("--features" "serde")
210213
;;

godot-codegen/src/generator/classes.rs

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,10 @@ struct GeneratedClassModule {
8080
}
8181

8282
struct Construction {
83-
constructor: TokenStream,
8483
construct_doc: &'static str,
8584
final_doc: Option<&'static str>,
8685
godot_default_impl: TokenStream,
86+
singleton_impl: TokenStream,
8787
}
8888

8989
fn make_class(class: &Class, ctx: &mut Context, view: &ApiView) -> GeneratedClass {
@@ -102,10 +102,10 @@ fn make_class(class: &Class, ctx: &mut Context, view: &ApiView) -> GeneratedClas
102102
};
103103

104104
let Construction {
105-
constructor,
106105
construct_doc,
107106
final_doc,
108107
godot_default_impl,
108+
singleton_impl,
109109
} = make_constructor_and_default(class, ctx);
110110

111111
let mut extended_class_doc = construct_doc.replace("Self", &class_name.rust_ty.to_string());
@@ -234,7 +234,7 @@ fn make_class(class: &Class, ctx: &mut Context, view: &ApiView) -> GeneratedClas
234234
#interface_trait
235235
#notification_enum
236236
impl #class_name {
237-
#constructor
237+
// Constructors all through traits: NewGd, NewAlloc, Singleton.
238238
#methods
239239
#notify_methods
240240
#internal_methods
@@ -267,6 +267,7 @@ fn make_class(class: &Class, ctx: &mut Context, view: &ApiView) -> GeneratedClas
267267
)*
268268

269269
#godot_default_impl
270+
#singleton_impl
270271
#deref_impl
271272
#inherits_macro_code
272273
}
@@ -424,34 +425,18 @@ fn make_constructor_and_default(class: &Class, ctx: &Context) -> Construction {
424425
// Note: this could use class_id() but is not yet done due to potential future lazy-load refactoring.
425426
//let class_name_obj = quote! { <Self as crate::obj::GodotClass>::class_id() };
426427

427-
let (constructor, construct_doc, has_godot_default_impl);
428+
let (construct_doc, has_godot_default_impl);
428429
if ctx.is_singleton(class_name) {
429-
// Note: we cannot return &'static mut Self, as this would be very easy to mutably alias.
430-
// &'static Self would be possible, but we would lose the whole mutability information (even if that is best-effort and
431-
// not strict Rust mutability, it makes the API much more usable).
432-
// As long as the user has multiple Gd smart pointers to the same singletons, only the internal raw pointers are aliased.
433-
// See also Deref/DerefMut impl for Gd.
434-
constructor = quote! {
435-
pub fn singleton() -> Gd<Self> {
436-
unsafe {
437-
let __class_name = #godot_class_stringname;
438-
let __object_ptr = sys::interface_fn!(global_get_singleton)(__class_name.string_sys());
439-
Gd::from_obj_sys(__object_ptr)
440-
}
441-
}
442-
};
443430
construct_doc = "# Singleton\n\n\
444-
This class is a singleton. You can get the one instance using [`Self::singleton()`][Self::singleton].";
431+
This class is a singleton. You can get the one instance using [`Singleton::singleton()`][crate::obj::Singleton::singleton].";
445432
has_godot_default_impl = false;
446433
} else if !class.is_instantiable {
447434
// Abstract base classes or non-singleton classes without constructor.
448-
constructor = TokenStream::new();
449435
construct_doc = "# Not instantiable\n\nThis class cannot be constructed. Obtain `Gd<Self>` instances via Godot APIs.";
450436
has_godot_default_impl = false;
451437
} else {
452438
// Manually managed classes (Object, Node, ...) as well as ref-counted ones (RefCounted, Resource, ...).
453439
// The constructors are provided as associated methods in NewGd::new_gd() and NewAlloc::new_alloc().
454-
constructor = TokenStream::new();
455440

456441
if class.is_refcounted {
457442
construct_doc = "# Construction\n\n\
@@ -488,11 +473,25 @@ fn make_constructor_and_default(class: &Class, ctx: &Context) -> Construction {
488473
TokenStream::new()
489474
};
490475

476+
let singleton_impl = if ctx.is_singleton(class_name) {
477+
let class_name = &class.name().rust_ty;
478+
quote! {
479+
impl crate::obj::Singleton for #class_name {
480+
fn singleton() -> crate::obj::Gd<Self> {
481+
// SAFETY: Class name matches type T, per code generator.
482+
unsafe { crate::classes::singleton_unchecked(&#godot_class_stringname) }
483+
}
484+
}
485+
}
486+
} else {
487+
TokenStream::new()
488+
};
489+
491490
Construction {
492-
constructor,
493491
construct_doc,
494492
final_doc,
495493
godot_default_impl,
494+
singleton_impl,
496495
}
497496
}
498497

@@ -573,8 +572,6 @@ fn make_class_method_definition(
573572
return FnDefinition::none();
574573
};
575574

576-
// Note: parameter type replacements (int -> enum) are already handled during domain mapping.
577-
578575
let rust_class_name = class.name().rust_ty.to_string();
579576
let rust_method_name = method.name();
580577
let godot_method_name = method.godot_name();

godot-core/src/builtin/callable.rs

Lines changed: 66 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use sys::{ffi_methods, ExtVariantType, GodotFfi};
1313
use crate::builtin::{inner, GString, StringName, Variant, VariantArray};
1414
use crate::meta::{GodotType, ToGodot};
1515
use crate::obj::bounds::DynMemory;
16-
use crate::obj::{Bounds, Gd, GodotClass, InstanceId};
16+
use crate::obj::{Bounds, Gd, GodotClass, InstanceId, Singleton};
1717
use crate::{classes, meta};
1818

1919
#[cfg(before_api = "4.3")]
@@ -72,7 +72,7 @@ impl Callable {
7272
/// If the builtin type does not have the method, the returned callable will be invalid.
7373
///
7474
/// Static builtin methods (e.g. `String.humanize_size`) are not supported in reflection as of Godot 4.4. For static _class_ functions,
75-
/// use [`from_local_static()`][Self::from_local_static] instead.
75+
/// use [`from_class_static()`][Self::from_class_static] instead.
7676
///
7777
/// _Godot equivalent: `Callable.create(Variant variant, StringName method)`_
7878
#[cfg(since_api = "4.3")]
@@ -84,17 +84,15 @@ impl Callable {
8484
inner::InnerCallable::create(variant, method_name)
8585
}
8686

87-
/// Create a callable for the static method `class_name::function` (single-threaded).
87+
/// Create a callable for the static method `class_name::function`
8888
///
89-
/// Allows you to call static functions through `Callable`.
89+
/// Allows you to call static functions through `Callable`. Allows both single- and multi-threaded calls; what happens on Godot side
90+
/// is your responsibility.
9091
///
91-
/// Does not support built-in types (such as `String`), only classes.
92-
///
93-
/// # Compatibility
94-
/// Not available before Godot 4.4. Library versions <0.3 used to provide this, however the polyfill used to emulate it was half-broken
95-
/// (not supporting signals, bind(), method_name(), is_valid(), etc).
92+
/// Does not support built-in types (such as `String`), only classes. Static functions on built-in types are not supported in Godot's
93+
/// reflection APIs at the moment.
9694
#[cfg(since_api = "4.4")]
97-
pub fn from_local_static(
95+
pub fn from_class_static(
9896
class_name: impl meta::AsArg<StringName>,
9997
function_name: impl meta::AsArg<StringName>,
10098
) -> Self {
@@ -103,16 +101,33 @@ impl Callable {
103101

104102
let callable_name = format!("{class_name}.{function_name}");
105103

106-
Self::from_local_fn(&callable_name, move |args| {
104+
let function = move |args: &[&Variant]| {
107105
let args = args.iter().cloned().cloned().collect::<Vec<_>>();
108106

109107
let result: Variant = classes::ClassDb::singleton().class_call_static(
110108
&class_name,
111109
&function_name,
112110
args.as_slice(),
113111
);
114-
Ok(result)
115-
})
112+
result
113+
};
114+
115+
#[cfg(feature = "experimental-threads")]
116+
let callable = Self::from_sync_fn(&callable_name, function);
117+
118+
#[cfg(not(feature = "experimental-threads"))]
119+
let callable = Self::from_local_fn(&callable_name, function);
120+
121+
callable
122+
}
123+
124+
#[deprecated = "Renamed to `from_class_static`."]
125+
#[cfg(since_api = "4.4")]
126+
pub fn from_local_static(
127+
class_name: impl meta::AsArg<StringName>,
128+
function_name: impl meta::AsArg<StringName>,
129+
) -> Self {
130+
Self::from_class_static(class_name, function_name)
116131
}
117132

118133
fn default_callable_custom_info() -> CallableCustomInfo {
@@ -139,14 +154,15 @@ impl Callable {
139154
///
140155
/// This constructor only allows the callable to be invoked from the same thread as creating it. If you need to invoke it from any thread,
141156
/// use [`from_sync_fn`][Self::from_sync_fn] instead (requires crate feature `experimental-threads`; only enable if really needed).
142-
pub fn from_local_fn<F, S>(name: S, rust_function: F) -> Self
157+
pub fn from_local_fn<R, F, S>(name: S, rust_function: F) -> Self
143158
where
144-
F: 'static + FnMut(&[&Variant]) -> Result<Variant, ()>,
159+
R: ToGodot,
160+
F: 'static + FnMut(&[&Variant]) -> R,
145161
S: meta::AsArg<GString>,
146162
{
147163
meta::arg_into_owned!(name);
148164

149-
Self::from_fn_wrapper(FnWrapper {
165+
Self::from_fn_wrapper::<F, R>(FnWrapper {
150166
rust_function,
151167
name,
152168
thread_id: Some(std::thread::current().id()),
@@ -165,12 +181,12 @@ impl Callable {
165181
pub fn from_linked_fn<F, T, S>(name: S, linked_object: &Gd<T>, rust_function: F) -> Self
166182
where
167183
T: GodotClass,
168-
F: 'static + FnMut(&[&Variant]) -> Result<Variant, ()>,
184+
F: 'static + FnMut(&[&Variant]) -> Variant,
169185
S: meta::AsArg<GString>,
170186
{
171187
meta::arg_into_owned!(name);
172188

173-
Self::from_fn_wrapper(FnWrapper {
189+
Self::from_fn_wrapper::<F, Variant>(FnWrapper {
174190
rust_function,
175191
name,
176192
thread_id: Some(std::thread::current().id()),
@@ -184,9 +200,10 @@ impl Callable {
184200
///
185201
/// After the first invocation, subsequent calls will panic with a message indicating the callable has already been consumed. This is
186202
/// useful for deferred operations that should only execute once. For repeated execution, use [`from_local_fn()][Self::from_local_fn].
187-
pub(crate) fn from_once_fn<F, S>(name: S, rust_function: F) -> Self
203+
pub(crate) fn from_once_fn<R, F, S>(name: S, rust_function: F) -> Self
188204
where
189-
F: 'static + FnOnce(&[&Variant]) -> Result<Variant, ()>,
205+
R: ToGodot,
206+
F: 'static + FnOnce(&[&Variant]) -> R,
190207
S: meta::AsArg<GString>,
191208
{
192209
meta::arg_into_owned!(name);
@@ -196,6 +213,7 @@ impl Callable {
196213
let rust_fn_once = rust_fn_once
197214
.take()
198215
.expect("callable created with from_once_fn() has already been consumed");
216+
199217
rust_fn_once(args)
200218
})
201219
}
@@ -204,7 +222,7 @@ impl Callable {
204222
#[doc(hidden)]
205223
pub fn __once_fn<F, S>(name: S, rust_function: F) -> Self
206224
where
207-
F: 'static + FnOnce(&[&Variant]) -> Result<Variant, ()>,
225+
F: 'static + FnOnce(&[&Variant]) -> Variant,
208226
S: meta::AsArg<GString>,
209227
{
210228
Self::from_once_fn(name, rust_function)
@@ -213,12 +231,12 @@ impl Callable {
213231
pub(crate) fn with_scoped_fn<S, F, Fc, R>(name: S, rust_function: F, callable_usage: Fc) -> R
214232
where
215233
S: meta::AsArg<GString>,
216-
F: FnMut(&[&Variant]) -> Result<Variant, ()>,
234+
F: FnMut(&[&Variant]) -> Variant,
217235
Fc: FnOnce(&Callable) -> R,
218236
{
219237
meta::arg_into_owned!(name);
220238

221-
let callable = Self::from_fn_wrapper(FnWrapper {
239+
let callable = Self::from_fn_wrapper::<F, Variant>(FnWrapper {
222240
rust_function,
223241
name,
224242
thread_id: Some(std::thread::current().id()),
@@ -248,14 +266,15 @@ impl Callable {
248266
/// });
249267
/// ```
250268
#[cfg(feature = "experimental-threads")]
251-
pub fn from_sync_fn<F, S>(name: S, rust_function: F) -> Self
269+
pub fn from_sync_fn<R, F, S>(name: S, rust_function: F) -> Self
252270
where
253-
F: 'static + Send + Sync + FnMut(&[&Variant]) -> Result<Variant, ()>,
271+
R: ToGodot,
272+
F: 'static + Send + Sync + FnMut(&[&Variant]) -> R,
254273
S: meta::AsArg<GString>,
255274
{
256275
meta::arg_into_owned!(name);
257276

258-
Self::from_fn_wrapper(FnWrapper {
277+
Self::from_fn_wrapper::<F, R>(FnWrapper {
259278
rust_function,
260279
name,
261280
thread_id: None,
@@ -287,9 +306,10 @@ impl Callable {
287306
Self::from_custom_info(info)
288307
}
289308

290-
fn from_fn_wrapper<F>(inner: FnWrapper<F>) -> Self
309+
fn from_fn_wrapper<F, R>(inner: FnWrapper<F>) -> Self
291310
where
292-
F: FnMut(&[&Variant]) -> Result<Variant, ()>,
311+
F: FnMut(&[&Variant]) -> R,
312+
R: ToGodot,
293313
{
294314
let object_id = inner.linked_object_id();
295315

@@ -298,7 +318,7 @@ impl Callable {
298318
let info = CallableCustomInfo {
299319
object_id,
300320
callable_userdata: Box::into_raw(Box::new(userdata)) as *mut std::ffi::c_void,
301-
call_func: Some(rust_callable_call_fn::<F>),
321+
call_func: Some(rust_callable_call_fn::<F, R>),
302322
free_func: Some(rust_callable_destroy::<FnWrapper<F>>),
303323
to_string_func: Some(rust_callable_to_string_named::<F>),
304324
is_valid_func: Some(rust_callable_is_valid),
@@ -593,7 +613,7 @@ mod custom_callable {
593613
/// Return `Ok(...)` if the call succeeded, and `Err(())` otherwise.
594614
/// Error handling is mostly needed in case argument number or types mismatch.
595615
#[allow(clippy::result_unit_err)] // TODO remove once there's a clear error type here.
596-
fn invoke(&mut self, args: &[&Variant]) -> Result<Variant, ()>;
616+
fn invoke(&mut self, args: &[&Variant]) -> Variant;
597617

598618
// TODO(v0.3): add object_id().
599619

@@ -616,37 +636,44 @@ mod custom_callable {
616636
) {
617637
let arg_refs: &[&Variant] = Variant::borrow_ref_slice(p_args, p_argument_count as usize);
618638

619-
let name = {
639+
#[cfg(debug_assertions)]
640+
let name = &{
620641
let c: &C = CallableUserdata::inner_from_raw(callable_userdata);
621642
c.to_string()
622643
};
623-
let ctx = meta::CallContext::custom_callable(name.as_str());
644+
#[cfg(not(debug_assertions))]
645+
let name = "<optimized out>";
646+
let ctx = meta::CallContext::custom_callable(name);
624647

625648
crate::private::handle_varcall_panic(&ctx, &mut *r_error, move || {
626649
// Get the RustCallable again inside closure so it doesn't have to be UnwindSafe.
627650
let c: &mut C = CallableUserdata::inner_from_raw(callable_userdata);
628651
let result = c.invoke(arg_refs);
629-
meta::varcall_return_checked(result, r_return, r_error);
652+
meta::varcall_return_checked(Ok(result), r_return, r_error);
630653
Ok(())
631654
});
632655
}
633656

634-
pub unsafe extern "C" fn rust_callable_call_fn<F>(
657+
pub unsafe extern "C" fn rust_callable_call_fn<F, R>(
635658
callable_userdata: *mut std::ffi::c_void,
636659
p_args: *const sys::GDExtensionConstVariantPtr,
637660
p_argument_count: sys::GDExtensionInt,
638661
r_return: sys::GDExtensionVariantPtr,
639662
r_error: *mut sys::GDExtensionCallError,
640663
) where
641-
F: FnMut(&[&Variant]) -> Result<Variant, ()>,
664+
F: FnMut(&[&Variant]) -> R,
665+
R: ToGodot,
642666
{
643667
let arg_refs: &[&Variant] = Variant::borrow_ref_slice(p_args, p_argument_count as usize);
644668

645-
let name = {
669+
#[cfg(debug_assertions)]
670+
let name = &{
646671
let w: &FnWrapper<F> = CallableUserdata::inner_from_raw(callable_userdata);
647672
w.name.to_string()
648673
};
649-
let ctx = meta::CallContext::custom_callable(name.as_str());
674+
#[cfg(not(debug_assertions))]
675+
let name = "<optimized out>";
676+
let ctx = meta::CallContext::custom_callable(name);
650677

651678
crate::private::handle_varcall_panic(&ctx, &mut *r_error, move || {
652679
// Get the FnWrapper again inside closure so the FnMut doesn't have to be UnwindSafe.
@@ -664,8 +691,8 @@ mod custom_callable {
664691
);
665692
}
666693

667-
let result = (w.rust_function)(arg_refs);
668-
meta::varcall_return_checked(result, r_return, r_error);
694+
let result = (w.rust_function)(arg_refs).to_variant();
695+
meta::varcall_return_checked(Ok(result), r_return, r_error);
669696
Ok(())
670697
});
671698
}

0 commit comments

Comments
 (0)