gdnative_core/export/signal.rs
1use crate::core_types::{GodotString, Variant, VariantType};
2use crate::export::{ClassBuilder, ExportInfo, NativeClass, PropertyUsage};
3
4/// Class to construct a signal. Make sure to call [`Self::done()`] in the end.
5///
6/// Signal parameters can be added with the various `param*()` methods.
7/// Keep in mind that unlike function parameters, signal parameters (both their lengths and types)
8/// are not statically checked in Godot. The parameter signature you specify is simply to assist you
9/// in the editor UI and with auto-generation of GDScript signal handlers.
10#[must_use = "SignalBuilder left unbuilt -- did you forget to call done()?"]
11pub struct SignalBuilder<'a, C> {
12 class_builder: &'a ClassBuilder<C>,
13 name: GodotString,
14 args: Vec<SignalParam>,
15}
16
17impl<'a, C: NativeClass> SignalBuilder<'a, C> {
18 pub(super) fn new(class_builder: &'a ClassBuilder<C>, signal_name: GodotString) -> Self {
19 Self {
20 class_builder,
21 name: signal_name,
22 args: vec![],
23 }
24 }
25
26 /// Add a parameter for the signal with a name and type.
27 ///
28 /// Note that GDScript signal parameters are generally untyped and not checked at runtime.
29 /// The type is solely used for UI purposes.
30 #[inline]
31 pub fn with_param(self, parameter_name: &str, parameter_type: VariantType) -> Self {
32 self.with_param_custom(SignalParam {
33 name: parameter_name.into(),
34 default: Variant::nil(),
35 export_info: ExportInfo::new(parameter_type),
36 usage: PropertyUsage::DEFAULT,
37 })
38 }
39
40 /// Add a parameter for the signal with a name and default value.
41 ///
42 /// The type is inferred from the default value.
43 /// Note that GDScript signal parameters are generally untyped and not checked at runtime.
44 /// The type is solely used for UI purposes.
45 #[inline]
46 pub fn with_param_default(self, parameter_name: &str, default_value: Variant) -> Self {
47 let variant_type = default_value.get_type();
48
49 self.with_param_custom(SignalParam {
50 name: parameter_name.into(),
51 default: default_value,
52 export_info: ExportInfo::new(variant_type),
53 usage: PropertyUsage::DEFAULT,
54 })
55 }
56
57 /// Add a (untyped) parameter for the signal with a name.
58 ///
59 /// Types are not required or checked at runtime, but they help for editor UI and auto-generation of signal listeners.
60 #[inline]
61 pub fn with_param_untyped(self, parameter_name: &str) -> Self {
62 // Note: the use of 'Nil' to express "untyped" is not following official documentation and could be improved.
63
64 self.with_param_custom(SignalParam {
65 name: parameter_name.into(),
66 default: Variant::nil(),
67 export_info: ExportInfo::new(VariantType::Nil),
68 usage: PropertyUsage::DEFAULT,
69 })
70 }
71
72 /// Add a parameter for the signal, manually configured.
73 #[inline]
74 pub fn with_param_custom(mut self, parameter: SignalParam) -> Self {
75 self.args.push(parameter);
76 self
77 }
78
79 /// Finish registering the signal.
80 #[inline]
81 pub fn done(self) {
82 self.class_builder.add_signal(Signal {
83 name: self.name,
84 args: self.args,
85 });
86 }
87}
88
89pub(crate) struct Signal {
90 pub name: GodotString,
91 pub args: Vec<SignalParam>,
92}
93
94/// Parameter in a signal declaration.
95///
96/// Instead of providing values for each field, check out the `param*()` methods in [`SignalBuilder`].
97pub struct SignalParam {
98 /// Parameter name.
99 pub name: GodotString,
100
101 /// Default value, used when no argument is provided.
102 pub default: Variant,
103
104 /// Metadata and UI hints about exporting, e.g. parameter type.
105 pub export_info: ExportInfo,
106
107 /// In which context the signal parameter is used.
108 pub usage: PropertyUsage,
109}