Skip to content

Commit b0d28df

Browse files
committed
Add SignalBuilder struct; rename SignalArgument -> SignalParam; integrate into ClassBuilder
1 parent 1c94e10 commit b0d28df

File tree

12 files changed

+234
-110
lines changed

12 files changed

+234
-110
lines changed

examples/dodge_the_creeps/src/hud.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,7 @@ pub struct Hud;
99
#[methods]
1010
impl Hud {
1111
fn register_hud(builder: &ClassBuilder<Self>) {
12-
builder.add_signal(Signal {
13-
name: "start_game",
14-
args: &[],
15-
});
12+
builder.signal("start_game").done();
1613
}
1714

1815
fn new(_owner: &CanvasLayer) -> Self {

examples/dodge_the_creeps/src/player.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,7 @@ pub struct Player {
1616
#[methods]
1717
impl Player {
1818
fn register_player(builder: &ClassBuilder<Self>) {
19-
builder.add_signal(Signal {
20-
name: "hit",
21-
args: &[],
22-
});
19+
builder.signal("hit").done()
2320
}
2421

2522
fn new(_owner: &Area2D) -> Self {

examples/signals/src/lib.rs

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,13 @@ struct SignalEmitter {
1212
#[methods]
1313
impl SignalEmitter {
1414
fn register_signals(builder: &ClassBuilder<Self>) {
15-
builder.add_signal(Signal {
16-
name: "tick",
17-
args: &[],
18-
});
15+
builder.signal("tick").done();
1916

20-
builder.add_signal(Signal {
21-
name: "tick_with_data",
17+
builder
18+
.signal("tick_with_data")
2219
// Argument list used by the editor for GUI and generation of GDScript handlers. It can be omitted if the signal is only used from code.
23-
args: &[SignalArgument {
24-
name: "data",
25-
default: Variant::new(100),
26-
export_info: ExportInfo::new(VariantType::I64),
27-
usage: PropertyUsage::DEFAULT,
28-
}],
29-
});
20+
.with_param_default("data", Variant::new(100))
21+
.done();
3022
}
3123

3224
fn new(_owner: &Node) -> Self {

gdnative-async/src/rt/func_state.rs

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
use gdnative_bindings::Reference;
2-
use gdnative_core::core_types::{ToVariant, Variant, VariantType};
2+
use gdnative_core::core_types::{ToVariant, Variant};
33
use gdnative_core::export::user_data::{LocalCellData, Map, MapMut};
44
use gdnative_core::export::{
5-
ClassBuilder, ExportInfo, NativeClass, NativeClassMethods, PropertyUsage, Signal,
6-
SignalArgument, StaticArgs, StaticArgsMethod,
5+
ClassBuilder, NativeClass, NativeClassMethods, StaticArgs, StaticArgsMethod,
76
};
87
use gdnative_core::godot_site;
98
use gdnative_core::object::ownership::Unique;
@@ -32,20 +31,12 @@ impl NativeClass for FuncState {
3231
}
3332

3433
fn register_properties(builder: &ClassBuilder<Self>) {
35-
builder.add_signal(Signal {
36-
name: "completed",
37-
args: &[SignalArgument {
38-
name: "value",
39-
default: Variant::nil(),
40-
export_info: ExportInfo::new(VariantType::Nil),
41-
usage: PropertyUsage::DEFAULT,
42-
}],
43-
});
44-
45-
builder.add_signal(Signal {
46-
name: "resumable",
47-
args: &[],
48-
});
34+
builder
35+
.signal("completed")
36+
.with_param_untyped("value")
37+
.done();
38+
39+
builder.signal("resumable").done();
4940
}
5041
}
5142

gdnative-core/src/export/class_builder.rs

Lines changed: 65 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,21 @@
1-
//! Low-level API to register and export GDNative classes, methods and properties.
2-
//!
3-
//! ## Init and exit hooks
4-
//!
5-
//! Three endpoints are automatically invoked by the engine during startup and shutdown:
6-
//!
7-
//! - [`godot_gdnative_init`],
8-
//! - [`godot_nativescript_init`],
9-
//! - [`godot_gdnative_terminate`],
10-
//!
11-
//! All three must be present. To quickly define all three endpoints using the default names,
12-
//! use [`godot_init`].
13-
//!
14-
//! ## Registering script classes
15-
//!
16-
//! [`InitHandle`] is the registry of all your exported symbols.
17-
//! To register script classes, call [`InitHandle::add_class`] or [`InitHandle::add_tool_class`]
18-
//! in your [`godot_nativescript_init`] or [`godot_init`] callback:
19-
//!
20-
//! ```ignore
21-
//! use gdnative::prelude::*;
22-
//!
23-
//! fn init(handle: InitHandle) {
24-
//! handle.add_class::<HelloWorld>();
25-
//! }
26-
//!
27-
//! godot_init!(init);
28-
//! ```
29-
//!
30-
//! For full examples, see [`examples`](https://github.com/godot-rust/godot-rust/tree/master/examples)
31-
//! in the godot-rust repository.
32-
1+
use crate::core_types::GodotString;
332
use std::ffi::CString;
343
use std::marker::PhantomData;
354
use std::ptr;
365

37-
use crate::core_types::{GodotString, Variant};
386
use crate::export::*;
397
use crate::object::NewRef;
408
use crate::private::get_api;
419

10+
// TODO unify string parameters across all buiders
11+
// Potential candidates:
12+
// * &str
13+
// * impl Into<GodotString>
14+
// * impl Into<Cow<'a, str>>
15+
16+
/// Allows registration of exported properties, methods and signals.
17+
///
18+
/// See member functions of this class for usage examples.
4219
#[derive(Debug)]
4320
pub struct ClassBuilder<C> {
4421
pub(super) init_handle: *mut libc::c_void,
@@ -141,37 +118,81 @@ impl<C: NativeClass> ClassBuilder<C> {
141118
PropertyBuilder::new(self, name)
142119
}
143120

121+
/// Returns a `SignalBuilder` which can be used to add a signal to the class being
122+
/// registered.
123+
///
124+
/// # Examples
125+
///
126+
/// Basic usage:
127+
///
128+
/// ```
129+
/// use gdnative::prelude::*;
130+
///
131+
/// #[derive(NativeClass)]
132+
/// #[inherit(Node)]
133+
/// #[register_with(Self::my_register)]
134+
/// #[no_constructor]
135+
/// struct MyType {}
136+
///
137+
/// // Note: no #[methods] required
138+
/// impl MyType {
139+
/// fn my_register(builder: &ClassBuilder<MyType>) {
140+
/// // Add signal without parameters
141+
/// builder
142+
/// .signal("jumped")
143+
/// .done();
144+
///
145+
/// // Add another signal with 1 parameter (untyped)
146+
/// builder
147+
/// .signal("fired")
148+
/// .with_param_untyped("weapon_type")
149+
/// .done();
150+
///
151+
/// // Add third signal with int + String parameters, the latter with a default value "Kerosene"
152+
/// builder
153+
/// .signal("used_jetpack")
154+
/// .with_param("fuel_spent", VariantType::I64)
155+
/// .with_param_default("fuel_type", Variant::new("Kerosene"))
156+
/// .done();
157+
/// }
158+
/// }
159+
/// ```
160+
#[inline]
161+
pub fn signal(&self, name: &str) -> SignalBuilder<C> {
162+
SignalBuilder::new(self, GodotString::from(name))
163+
}
164+
144165
#[inline]
145-
pub fn add_signal(&self, signal: Signal) {
166+
pub(crate) fn add_signal(&self, signal: Signal) {
146167
unsafe {
147-
let name = GodotString::from_str(signal.name);
148-
let owned = signal
168+
let args_and_hints = signal
149169
.args
150170
.iter()
151171
.map(|arg| {
152-
let arg_name = GodotString::from_str(arg.name);
153172
let hint_string = arg.export_info.hint_string.new_ref();
154-
(arg, arg_name, hint_string)
173+
(arg, hint_string)
155174
})
156175
.collect::<Vec<_>>();
157-
let mut args = owned
176+
177+
let mut sys_args = args_and_hints
158178
.iter()
159-
.map(|(arg, arg_name, hint_string)| sys::godot_signal_argument {
160-
name: arg_name.to_sys(),
179+
.map(|(arg, hint_string)| sys::godot_signal_argument {
180+
name: arg.name.to_sys(),
161181
type_: arg.default.get_type() as i32,
162182
hint: arg.export_info.hint_kind,
163183
hint_string: hint_string.to_sys(),
164184
usage: arg.usage.to_sys(),
165185
default_value: arg.default.to_sys(),
166186
})
167187
.collect::<Vec<_>>();
188+
168189
(get_api().godot_nativescript_register_signal)(
169190
self.init_handle,
170191
self.class_name.as_ptr(),
171192
&sys::godot_signal {
172-
name: name.to_sys(),
173-
num_args: args.len() as i32,
174-
args: args.as_mut_ptr(),
193+
name: signal.name.to_sys(),
194+
num_args: sys_args.len() as i32,
195+
args: sys_args.as_mut_ptr(),
175196
num_default_args: 0,
176197
default_args: ptr::null_mut(),
177198
},
@@ -211,15 +232,3 @@ impl<C: NativeClass> ClassBuilder<C> {
211232
}
212233
}
213234
}
214-
215-
pub struct Signal<'l> {
216-
pub name: &'l str,
217-
pub args: &'l [SignalArgument<'l>],
218-
}
219-
220-
pub struct SignalArgument<'l> {
221-
pub name: &'l str,
222-
pub default: Variant,
223-
pub export_info: ExportInfo,
224-
pub usage: PropertyUsage,
225-
}

gdnative-core/src/export/method.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ use crate::object::ownership::Shared;
1212
use crate::object::{Ref, TInstance, TRef};
1313

1414
/// Builder type used to register a method on a `NativeClass`.
15+
#[must_use = "MethodBuilder left unbuilt -- did you forget to call done() or done_stateless()?"]
1516
pub struct MethodBuilder<'a, C, F> {
16-
class_builder: &'a super::ClassBuilder<C>,
17+
class_builder: &'a ClassBuilder<C>,
1718
name: &'a str,
1819
method: F,
1920

@@ -66,7 +67,7 @@ where
6667
F: Method<C> + Copy + Default,
6768
{
6869
/// Register the method as a stateless method. Stateless methods do not have data
69-
/// pointers and destructors and is thus slightly lighter. This is intended for ZSTs,
70+
/// pointers and destructors and are thus slightly lighter. This is intended for ZSTs,
7071
/// but can be used with any `Method` type with `Copy + Default`.
7172
#[inline]
7273
pub fn done_stateless(self) {

gdnative-core/src/export/mod.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,48 @@
22
//!
33
//! NativeScript allows users to have their own scripts in a native language (in this case Rust).
44
//! It is _not_ the same as GDNative, the native interface to call into Godot.
5-
//!
65
//! Symbols in this module allow registration, exporting and management of user-defined types
76
//! which are wrapped in native scripts.
87
//!
98
//! If you are looking for how to manage Godot core types or classes (objects), check
109
//! out the [`core_types`][crate::core_types] and [`object`][crate::object] modules, respectively.
10+
//!
11+
//! ## Init and exit hooks
12+
//!
13+
//! Three endpoints are automatically invoked by the engine during startup and shutdown:
14+
//!
15+
//! * [`godot_gdnative_init`],
16+
//! * [`godot_nativescript_init`],
17+
//! * [`godot_gdnative_terminate`],
18+
//!
19+
//! All three must be present. To quickly define all three endpoints using the default names,
20+
//! use [`godot_init`].
21+
//!
22+
//! ## Registering script classes
23+
//!
24+
//! [`InitHandle`] is the registry of all your exported symbols.
25+
//! To register script classes, call [`InitHandle::add_class()`] or [`InitHandle::add_tool_class()`]
26+
//! in your [`godot_nativescript_init`] or [`godot_init`] callback:
27+
//!
28+
//! ```ignore
29+
//! use gdnative::prelude::*;
30+
//!
31+
//! fn init(handle: InitHandle) {
32+
//! handle.add_class::<HelloWorld>();
33+
//! }
34+
//!
35+
//! godot_init!(init);
36+
//! ```
37+
//!
38+
//! For full examples, see [`examples`](https://github.com/godot-rust/godot-rust/tree/master/examples)
39+
//! in the godot-rust repository.
1140
1241
mod class;
1342
mod class_builder;
1443
mod macros;
1544
mod method;
1645
mod property;
46+
mod signal;
1747

1848
pub(crate) mod class_registry;
1949
pub(crate) mod emplace;
@@ -26,3 +56,4 @@ pub use class::*;
2656
pub use class_builder::*;
2757
pub use method::*;
2858
pub use property::*;
59+
pub use signal::*;

gdnative-core/src/export/property.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ impl ExportInfo {
6464

6565
/// Builder type used to register a property on a `NativeClass`.
6666
#[derive(Debug)]
67-
#[must_use]
67+
#[must_use = "PropertyBuilder left unbuilt -- did you forget to call done()?"]
6868
pub struct PropertyBuilder<'a, C, T: Export, S = InvalidSetter<'a>, G = InvalidGetter<'a>> {
6969
name: &'a str,
7070
setter: S,
@@ -161,6 +161,8 @@ where
161161

162162
/// Provides a setter function with the signature `fn(&C, owner: C::Base, value: T)`
163163
/// where `C` is the `NativeClass` type being registered and `T` is the type of the property.
164+
///
165+
/// "shr" stands for "shared reference", as opposed to the more common `&mut self`.
164166
#[inline]
165167
pub fn with_shr_setter<NS>(
166168
self,

0 commit comments

Comments
 (0)