Skip to content

Commit f7bce47

Browse files
authored
Migrate #[export] -> #[method] (#78)
Merging, now that gdnative 0.10.1 has been released.
1 parent d4ccd28 commit f7bce47

File tree

11 files changed

+110
-114
lines changed

11 files changed

+110
-114
lines changed

src/faq/code.md

Lines changed: 39 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ struct MyNode {
3030

3131
#[methods]
3232
impl MyNode {
33-
#[export]
34-
fn _ready(&self, owner: TRef<Node>) {
33+
#[method]
34+
fn _ready(&self, #[base] base: TRef<Node>) {
3535
let node = Node::new();
36-
owner.add_child(node);
36+
base.add_child(node);
3737
self.node_ref = Some(node.claim());
3838
}
3939
}
@@ -67,18 +67,20 @@ impl SignalEmitter {
6767
builder.signal("updated").done();
6868
}
6969

70-
fn new(_owner: &Node) -> Self {
70+
fn new(_base: &Node) -> Self {
7171
SignalEmitter {
7272
data: "initial",
7373
}
7474
}
75-
#[export]
76-
fn update_data(&mut self, owner: TRef<Node>, data: LargeData) {
75+
76+
#[method]
77+
fn update_data(&mut self, #[base] base: TRef<Node>, data: LargeData) {
7778
self.data = data;
78-
owner.emit_signal("updated", &[]);
79+
base.emit_signal("updated", &[]);
7980
}
80-
#[export]
81-
fn get_data(&self, owner: TRef<Node>) -> &LargeData {
81+
82+
#[method]
83+
fn get_data(&self) -> &LargeData {
8284
&self.data
8385
}
8486
}
@@ -94,13 +96,14 @@ There are two ways to solve it.
9496
2. Store `data` in a `RefCell<LargeData>` if it should only be accessed from the same thread (such as with signals) or `Mutex<LargeData>` if you need thread-safety. Then you can modify `update_data()` to the following snippet:
9597

9698
```rust
97-
fn update_data(&self, owner: TRef<Node>, data: LargeData) {
98-
// If using RefCell
99-
self.data.replace(data);
100-
// If using Mutex
101-
// *self.data.lock().expect("this should work") = data;
102-
owner.emit_signal("updated", &[]);
103-
}
99+
#[method]
100+
fn update_data(&self, #[base] base: TRef<Node>, data: LargeData) {
101+
// If using RefCell
102+
self.data.replace(data);
103+
// If using Mutex
104+
// *self.data.lock().expect("this should work") = data;
105+
base.emit_signal("updated", &[]);
106+
}
104107
```
105108

106109
In both instances you will not encounter the reentrant errors.
@@ -128,9 +131,9 @@ One of the ways that godot-rust avoids large `unsafe` blocks is by using the [Ty
128131
Here is an example of some common `unsafe` usage that you will often see and use in your own games.
129132

130133
```rust
131-
fn get_a_node(&self, owner: TRef<Node>) {
134+
fn get_a_node(&self, #[base] base: TRef<Node>) {
132135
// This is safe because it returns an option that Rust knows how to check.
133-
let child = owner.get_child("foo");
136+
let child = base.get_child("foo");
134137
// This is safe because Rust panics if the returned `Option` is None.
135138
let child = child.expect("I know this should exist");
136139
// This is also safe because Rust panics if the returned `Option` is None.
@@ -177,14 +180,14 @@ struct Enemy {
177180

178181
#[methods]
179182
impl Enemy {
180-
fn new(_owner: &Object) -> Self {
183+
fn new(_base: &Object) -> Self {
181184
Enemy {
182185
data: None,
183186
}
184187
}
185188

186-
#[export]
187-
fn set_data(&mut self, _owner: &Object, name: String, health: f32) {
189+
#[method]
190+
fn set_data(&mut self, name: String, health: f32) {
188191
self.data = Some(EnemyData { name, health });
189192
}
190193
}
@@ -215,8 +218,8 @@ struct EntityFactory {}
215218

216219
#[methods]
217220
impl EntityFactory {
218-
#[export]
219-
fn enemy(&self, _owner: &Reference, name: String, health: f32)
221+
#[method]
222+
fn enemy(&self, name: String, health: f32)
220223
-> Instance<Enemy, Unique> {
221224
Enemy { name, health }.emplace()
222225
}
@@ -240,8 +243,8 @@ pub struct StaticUtil;
240243

241244
#[methods]
242245
impl StaticUtil {
243-
#[export]
244-
fn compute_something(&self, _owner: &Object, input: i32) -> i32 {
246+
#[method]
247+
fn compute_something(&self, input: i32) -> i32 {
245248
godot_print!("pseudo-static computation");
246249
2 * input
247250
}
@@ -277,8 +280,8 @@ pub struct AnotherNativeScript;
277280

278281
#[methods]
279282
impl AnotherNativeScript {
280-
#[export]
281-
pub fn method_accepting_my_node(&self, _owner: &Reference, my_node: Variant) {
283+
#[method]
284+
pub fn method_accepting_my_node(&self, my_node: Variant) {
282285
// 1. Cast Variant to Ref of associated Godot type, and convert to TRef.
283286
let my_node = unsafe {
284287
my_node
@@ -294,7 +297,7 @@ impl AnotherNativeScript {
294297

295298
// 3. Map over the RefInstance to process the underlying user data.
296299
my_node
297-
.map(|my_node, _owner| {
300+
.map(|my_node, _base| {
298301
// Now my_node is of type MyNode2D.
299302
})
300303
.expect("Failed to map over my_node instance");
@@ -397,10 +400,10 @@ struct MyNode {
397400

398401
#[methods]
399402
impl MyNode {
400-
#[export]
401-
fn _ready(&self, owner: TRef<Node>) {
403+
#[method]
404+
fn _ready(&self, #[base] base: TRef<Node>) {
402405
// Get an existing child node that is a Godot class.
403-
let node2d = owner
406+
let node2d = base
404407
.get_node("Node2D")
405408
.expect("this node must have a child with the path `Node2D`");
406409
let node2d = unsafe { node2d.assume_safe() };
@@ -409,7 +412,7 @@ impl MyNode {
409412
self.node2d = Some(node2d.claim());
410413

411414
// Get an existing child node that is a Rust class.
412-
let instance = owner
415+
let instance = base
413416
.get_node("MyClass")
414417
.expect("this node must have a child with the path `MyClass`");
415418
let instance = unsafe { instance.assume_safe() };
@@ -447,7 +450,7 @@ For more information about the Godot profiler, please refer to the [official doc
447450
In order for Godot to profile your function, all the following must be true:
448451
- The function belongs to a struct that derives `NativeClass`.
449452
- The function is included in an `impl` block that is attributed with the `#[methods]` attribute.
450-
- The function is attributed with `#[export]` attribute.
453+
- The function is attributed with `#[method]` attribute.
451454

452455
As such, this method is _only_ useful for exported code and is subject to the Godot profiler's limitations, such as millisecond accuracy in profiler metrics.
453456

@@ -460,13 +463,13 @@ struct MyClass {}
460463

461464
#[methods]
462465
impl MyClass {
463-
fn new(_owner: &Node) -> Self {
466+
fn new(_base: &Node) -> Self {
464467
Self {}
465468
}
466469

467-
#[export]
470+
#[method]
468471
#[gdnative::profiled]
469-
fn my_profiled_function(&self, _owner: &Node) {
472+
fn my_profiled_function(&self, #[base] _base: &Node) {
470473
// Any code in this function will be profiled.
471474
}
472475
}

src/faq/configuration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ Yes, any Rust struct that inherits from `NativeClass` can be also used as a tool
8585
stuct MyTool {}
8686
#[methods]
8787
impl MyTool {
88-
fn new (_owner: &Node) -> Self {
88+
fn new (_base: &Node) -> Self {
8989
Self {}
9090
}
9191
}

src/gdnative-overview/wrappers.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ pub struct Player {
7878

7979
#[methods]
8080
impl Player {
81-
fn new(_owner: &Reference) -> Self {
81+
fn new(_base: &Reference) -> Self {
8282
Self {
8383
name: "New player".to_string(),
8484
score: 0

src/getting-started/hello-world.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ Unfortunately, this won't compile just yet: Rust will complain about the lack of
118118
// You may add any number of ordinary `impl` blocks as you want. However, ...
119119
impl HelloWorld {
120120
/// The "constructor" of the class.
121-
fn new(_owner: &Node) -> Self {
121+
fn new(_base: &Node) -> Self {
122122
HelloWorld
123123
}
124124
}
@@ -156,24 +156,24 @@ You can now run your project from the editor! If all goes correctly, it should l
156156
#[methods]
157157
impl HelloWorld {
158158

159-
// To make a method known to Godot, use the #[export] attribute.
159+
// To make a method known to Godot, use the #[method] attribute.
160160
// In Godot, script "classes" do not actually inherit the parent class.
161-
// Instead, they are "attached" to the parent object, called the "owner".
161+
// Instead, they are "attached" to the parent object, called the "base".
162162
//
163-
// In order to enable access to the owner, it is passed as the second
164-
// argument to every single exposed method. As a result, all exposed
165-
// methods MUST have `owner: &BaseClass` as their second arguments,
166-
// before all other arguments in the signature.
167-
#[export]
168-
fn _ready(&self, _owner: &Node) {
163+
// If access to the base instance is desired, the 2nd parameter can be
164+
// annotated with #[base]. It must have type `&T` or `TRef<T>`, where `T`
165+
// is the base type specified in #[inherit]. If you don't need this parameter,
166+
// feel free to omit it entirely.
167+
#[method]
168+
fn _ready(&self, #[base] base: &Node) {
169169
// The `godot_print!` macro works like `println!` but prints to the Godot-editor
170170
// output tab as well.
171-
godot_print!("Hello, world!");
171+
godot_print!("Hello world from node {}!", base.to_string());
172172
}
173173
}
174174
```
175175

176-
Here, the `#[export]` attribute is used to tell godot-rust to expose your methods to Godot. In this case, we are overriding [`_ready`](https://docs.godotengine.org/en/stable/classes/class_node.html#class-node-method-ready) and printing a line of text.
176+
Here, the `#[method]` attribute is used to tell godot-rust to expose your methods to Godot. In this case, we are overriding [`_ready`](https://docs.godotengine.org/en/stable/classes/class_node.html#class-node-method-ready) and printing a line of text.
177177

178178
Now, re-compile the crate using `cargo build` and copy the resulting binary to the Godot project. Launch the project from the editor, and you should see `Hello, world!` in the Godot console!
179179

src/recipes/async-tokio.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ struct AsyncExecutorDriver {
6161
}
6262

6363
impl AsyncExecutorDriver {
64-
fn new(_owner: &Node) -> Self {
64+
fn new(_base: &Node) -> Self {
6565
AsyncExecutorDriver {
6666
runtime: Builder::new_current_thread()
6767
.enable_io() // optional, depending on your needs
@@ -78,8 +78,8 @@ In the `_process` call of our `AsyncExecutorDriver`, we can block on `run_until`
7878
```rust
7979
#[methods]
8080
impl AsyncExecutorDriver {
81-
#[export]
82-
fn _process(&self, _owner: &Node, _delta: f64) {
81+
#[method]
82+
fn _process(&self, #[base] _base: &Node, _delta: f64) {
8383
EXECUTOR.with(|e| {
8484
self.runtime
8585
.block_on(async {

src/recipes/logging.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -134,24 +134,24 @@ impl DebugLogger {
134134
fn new(_: &Node) -> Self {
135135
Self {}
136136
}
137-
#[export]
138-
fn error(&self, _owner: &Node, target: String, message: String) {
137+
#[method]
138+
fn error(&self, target: String, message: String) {
139139
log::error!(target: &target, "{}", message);
140140
}
141-
#[export]
142-
fn warn(&self, _: &Node, target: String, message: String) {
141+
#[method]
142+
fn warn(&self, target: String, message: String) {
143143
log::warn!(target: &target, "{}", message);
144144
}
145-
#[export]
146-
fn info(&self, _: &Node, target: String, message: String) {
145+
#[method]
146+
fn info(&self, target: String, message: String) {
147147
log::info!(target: &target, "{}", message);
148148
}
149-
#[export]
150-
fn debug(&self, _: &Node, target: String, message: String) {
149+
#[method]
150+
fn debug(&self, target: String, message: String) {
151151
log::debug!(target: &target, "{}", message);
152152
}
153-
#[export]
154-
fn trace(&self, _: &Node, target: String, message: String) {
153+
#[method]
154+
fn trace(&self, target: String, message: String) {
155155
log::trace!(target: &target, "{}", message);
156156
}
157157
}

src/rust-binding/calling-gdscript.md

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ pub struct Enemy {
3636

3737
#[methods]
3838
impl Enemy {
39-
#[export]
40-
fn _to_string(&self, _owner: &Reference) -> String {
39+
#[method]
40+
fn _to_string(&self) -> String {
4141
format!("{:?}", self) // calls Debug::fmt()
4242
}
4343
}
@@ -51,16 +51,13 @@ fn init(handle: InitHandle) {
5151
```
5252
Now, it's not possible to directly return `Enemy` instances in exported methods, so this won't work:
5353
```rust
54-
#[export]
55-
fn create_enemy(&mut self, _owner: &Node) -> Enemy {...}
54+
#[method]
55+
fn create_enemy(&mut self) -> Enemy {...}
5656
```
5757
Instead, you can wrap the object in a `Instance<Enemy, Unique>`, using `emplace()`. For an in-depth explanation of the `Instance` class, read [this section](../gdnative-overview/wrappers.md#instance-reference-with-attached-rust-class).
5858
```rust
59-
#[export]
60-
fn create_enemy(
61-
&self,
62-
_owner: &Node
63-
) -> Instance<Enemy, Unique> {
59+
#[method]
60+
fn create_enemy(&self) -> Instance<Enemy, Unique> {
6461
let enemy = Enemy {
6562
pos: Vector2::new(7.0, 2.0),
6663
health: 100.0,
@@ -177,7 +174,7 @@ When calling GDScript functions from Rust, a few things need to be kept in mind.
177174

178175
**Safety:** Since the calls are dynamic, it is possible to invoke any other functions through them, including unsafe ones like `free()`. As a result, `call()` and its alternatives are unsafe.
179176

180-
**Re-entrancy:** When calling from Rust to GDScript, your Rust code is usually already running in an exported `#[export]` method, meaning that it has bound its receiver object via `&T` or `&mut T` reference. In the GDScript code, you must not invoke any method on the same Rust receiver, which would violate safety rules (aliasing of `&mut`).
177+
**Re-entrancy:** When calling from Rust to GDScript, your Rust code is usually already running in an exported `#[method]` method, meaning that it has bound its receiver object via `&T` or `&mut T` reference. In the GDScript code, you must not invoke any method on the same Rust receiver, which would violate safety rules (aliasing of `&mut`).
181178

182179

183180
## Signal emissions

src/rust-binding/classes.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,15 @@ pub struct GodotApi {}
5252
#[methods]
5353
impl GodotApi {
5454
// Constructor, either:
55-
fn new(owner: &Node) -> Self { ... }
55+
fn new(base: &Node) -> Self { ... }
5656
// or:
57-
fn new(owner: TRef<Node>) -> Self { ... }
57+
fn new(base: TRef<Node>) -> Self { ... }
5858
}
5959
```
6060

6161
The [`#[derive(NativeClass)]` macro](https://docs.rs/gdnative/latest/gdnative/derive.NativeClass.html) enables a Rust type to be usable as a _native class_ in Godot. It implements [the `NativeClass` trait](https://docs.rs/gdnative/latest/gdnative/nativescript/trait.NativeClass.html), which fills in the glue code required to make the class available in Godot. Among other information, this includes class name and registry of exported methods and properties. For the user, the utility methods `new_instance()` and `emplace()` are provided for constructing `Instance` objects.
6262

63-
The function `new()` corresponds to `_init()` in GDScript. The _owner_ is the base object of the script, and must correspond to the class specified in the `#[inherit]` attribute (or `Reference` if the attribute is absent). The parameter can be a shared reference `&T` or a `TRef<T>`.
63+
The function `new()` corresponds to `_init()` in GDScript. The _base_ is the base object of the script, and must correspond to the class specified in the `#[inherit]` attribute (or `Reference` if the attribute is absent). The parameter can be a shared reference `&T` or a `TRef<T>`.
6464

6565
With a `new()` method, you are able to write `GodotApi.new()` in GDScript. If you don't need this, you can add the `#[no_constructor]` attribute to the struct declaration.
6666

0 commit comments

Comments
 (0)