Skip to content

Support @export_node_path attribute - #1620

Merged
Bromeon merged 1 commit into
godot-rust:masterfrom
tuto193:implement_export_node_path
Jun 2, 2026
Merged

Bromeon merged 1 commit into
godot-rust:masterfrom
tuto193:implement_export_node_path

Conversation

@tuto193

@tuto193 tuto193 commented May 27, 2026

Copy link
Copy Markdown
Contributor

Added support for export_node_path annotation (Completes #1128)

Adds the ability to annotate fields with @export_node_path:

#[derive(GodotClass)]
#[class(base=Node2D)]
struct SomeClass {
    /// Equivalent to:
    /// ```gdscript
    /// @export_node_path("Button", "TouchScreenButton") var some_button: NodePath
    /// ```
    #[export(node_path = ("Button", "TouchScreenButton"))]
    some_button: NodePath,

    base: Base<Node2D>
}

Note: I didn't find the exact PR where export_node_path was introduced to GDScript upstream, so if it's needed let me know, and I will dig deeper. Otherwise let me know if I should adjust any of these changes.

Couldn't have done it without other PRs like those of @Swivelgames on #1183. It really made it a lot easier to have that as reference, so thanks to them a lot!

@tuto193
tuto193 force-pushed the implement_export_node_path branch from de6a99d to e2d03ab Compare May 27, 2026 10:02
@GodotRust

Copy link
Copy Markdown

API docs are being generated and will be shortly available at: https://godot-rust.github.io/docs/gdext/pr-1620

@TitanNano TitanNano added feature Adds functionality to the library c: register Register classes, functions and other symbols to GDScript labels May 27, 2026

@Bromeon Bromeon left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot, this is a nice addition! πŸ‘

PR looks mostly good, added some comments on smaller parts.

Comment thread itest/rust/build.rs Resolved
Comment thread itest/rust/build.rs Resolved
Comment thread itest/rust/build.rs Resolved
Comment on lines +190 to +198
// Detect parenthesized list: node_path = ("Button", "TouchScreenButton")
if tokens.len() == 1
&& let TokenTree::Group(group) = &tokens[0]
&& group.delimiter() == Delimiter::Parenthesis
{
let list_parser = ListParser::new_from_tree(
tokens.into_iter().next().unwrap(),
Delimiter::Parenthesis,
)?;

@Bromeon Bromeon May 28, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this hand-parsing of tokens really needed before you pass it to ListParser?

How do other godot-rust proc-macro APIs that deal with lists do it?

@tuto193 tuto193 May 28, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been breaking my head a bit with this today. I'm not using the handle_list(), since I thought, we would allow
[Option 1]

  // ...
  #[export(node_path = "Class1")] // (not a list)
  // ...

as a valid case.

Otherwise I get the error:

...
error: expected list of items
    --> /Users/carlosfernandez/Git/gdext/target/debug/build/itest-c56514b7f101be8d/out/gen_ffi.rs:2412:30
     |
2412 |         #[export(node_path = "Button")]
     |                              ^^^^^^^^
...

If we were to parse this only as a list, the above wouldn't work, and instead we would need to only allow:
[Option 2]

// ..
  #[export(node_path = ("Class1"))]. // (list with only one entry)
// ...
}

I'm removing the [Option 1] for now though, since it's more in line with what is done in GDScript.

@Bromeon Bromeon May 28, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need both? I guess the one with 1 argument is the common one?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left [Option 2] (#[export(node_path = ("Class1", ...))]) in. I think it's indeed more in line with what users could use, plus allows for more freedom/flexibility. Also, I will mark this as resolved unless you (or anyone else) is really against this, although I personally like the freedom plus it's the code is as easy to maintain as the other handle_list() branches :)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't resolve conversations you still expect me to read, it's rather hard to locate them πŸ™‚

But sounds good for now, we can always add the other syntax later.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad πŸ˜….

So I will leave it as is :)

@tuto193
tuto193 force-pushed the implement_export_node_path branch from e2d03ab to 86b6b08 Compare May 28, 2026 13:35
@Bromeon
Bromeon added this pull request to the merge queue Jun 2, 2026
Merged via the queue into godot-rust:master with commit e21dddf Jun 2, 2026
23 checks passed
TW0hank0 added a commit to TW0hank0/positive_mahjong that referenced this pull request Aug 19, 2026
Update patch dependencies

This MR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [console_error_panic_hook](https://github.com/rustwasm/console_error_panic_hook) | workspace.dependencies | patch | `=0.1.5` β†’ `=0.1.7` |
| [godot](https://godot-rust.github.io) ([source](https://github.com/godot-rust/gdext)) | workspace.dependencies | patch | `=0.5.3` β†’ `=0.5.5` |
| [serde](https://serde.rs) ([source](https://github.com/serde-rs/serde)) | workspace.dependencies | patch | `=1.0.228` β†’ `=1.0.229` |
| [serde_json](https://github.com/serde-rs/json) | workspace.dependencies | patch | `=1.0.149` β†’ `=1.0.151` |

---

### Release Notes

<details>
<summary>rustwasm/console_error_panic_hook (console_error_panic_hook)</summary>

### [`v0.1.6`](rustwasm/console_error_panic_hook@0.1.5...0.1.6)

[Compare Source](rustwasm/console_error_panic_hook@0.1.5...0.1.6)

</details>

<details>
<summary>godot-rust/gdext (godot)</summary>

### [`v0.5.5`](https://github.com/godot-rust/gdext/blob/HEAD/Changelog.md#v055)

[Compare Source](godot-rust/gdext@v0.5.4...v0.5.5)

*9 August 2026*

##### 🌻 Features

- `EngineBitfield`: add `with()` and `without()` methods ([#&#8203;1627](godot-rust/gdext#1627))
- `#[func(virtual)]` now supports `async fn` for GDScript coroutines ([#&#8203;1645](godot-rust/gdext#1645))
- Add `PhantomData<T>` support for `GodotConvert` derive macro ([#&#8203;1619](godot-rust/gdext#1619))

##### πŸ“ˆ Performance

- Singletons are now cached ([#&#8203;1636](godot-rust/gdext#1636))
- Cache user singleton pointers ([#&#8203;1644](godot-rust/gdext#1644))
- Cheaper refcount operations ([#&#8203;1669](godot-rust/gdext#1669))

##### 🧹 Quality of life

- Always use godot\_error in panic hook ([#&#8203;1647](godot-rust/gdext#1647))
- Rename `cast_int/cast_float` to `to_vector*/to_rect*` ([#&#8203;1661](godot-rust/gdext#1661))
- Validate class registrations against `ClassDB` ([#&#8203;1664](godot-rust/gdext#1664))

##### πŸ› οΈ Bugfixes

- Fix `#[var(pub)]` panic during `OnEditor<Gd<T>>` reload ([#&#8203;1639](godot-rust/gdext#1639))
- Fix async `SignalFuture` panic when object is freed before exit flag ([#&#8203;1648](godot-rust/gdext#1648))
- Fix `api-custom` build when prebuilt lags detected Godot version ([#&#8203;1649](godot-rust/gdext#1649))
- Harden various parts of codebase ([#&#8203;1660](godot-rust/gdext#1660))
- Fix `GFile` `BufRead` past EOF ([#&#8203;1670](godot-rust/gdext#1670))

##### πŸ—οΈ Maintenance

- Replace `godot-cell` borrow-state proptests with exhaustive model check ([#&#8203;1650](godot-rust/gdext#1650))
- Make accidental access of `#[doc(hidden)]` symbols more explicit ([#&#8203;1651](godot-rust/gdext#1651))
- Follow-up to rustc / Godot changes ([#&#8203;1659](godot-rust/gdext#1659))
- Name virtual-callback layers after user-facing `I*` virtuals ([#&#8203;1662](godot-rust/gdext#1662))
- Move ref-counting operations from `DynMemory` to `RawGd` ([#&#8203;1667](godot-rust/gdext#1667))

### [`v0.5.4`](https://github.com/godot-rust/gdext/blob/HEAD/Changelog.md#v054)

[Compare Source](godot-rust/gdext@v0.5.3...v0.5.4)

*23 June 2026*

##### 🌻 Features

- Godot 4.7: add `api-4-7` level ([#&#8203;1641](godot-rust/gdext#1641))
- Type-Safe API for User-defined RPCs ([#&#8203;1535](godot-rust/gdext#1535), [#&#8203;1634](godot-rust/gdext#1634))
- String conversions: ` to_gstring()`, `to_string_name()` etc ([#&#8203;1623](godot-rust/gdext#1623))
- Thread-safe FFI scaffolding + cross-thread printing ([#&#8203;1632](godot-rust/gdext#1632))
- `Gd` introspection APIs: `dynamic_class`, `is_dynamic_class[_of]`, `is_ref_counted` ([#&#8203;1631](godot-rust/gdext#1631))
- Support async versions of `tools::load()` and `tools::try_load()` ([#&#8203;1601](godot-rust/gdext#1601))
- Support `@export_node_path` attribute ([#&#8203;1620](godot-rust/gdext#1620))

##### 🧹 Quality of life

- Slightly more flexible `GodotStringExt` through unsized impls ([#&#8203;1629](godot-rust/gdext#1629))
- Suppress Godot errors in fallible functions ([#&#8203;1637](godot-rust/gdext#1637))

##### πŸ› οΈ Bugfixes

- Fix Linux hot-reload panic when TLS destructors fire before init ([#&#8203;1611](godot-rust/gdext#1611))
- Fix panic-in-drop in future tests; harden against race conditions ([#&#8203;1617](godot-rust/gdext#1617))
- Auto-remove custom callables also when connected in untyped APIs ([#&#8203;1612](godot-rust/gdext#1612))
- Fix async panics at shutdown ([#&#8203;1625](godot-rust/gdext#1625))
- Fix `Object` returns with dynamic type `RefCounted` ([#&#8203;1628](godot-rust/gdext#1628))
- Fix memory leak for `connect_self()` on `RefCounted` ([#&#8203;1635](godot-rust/gdext#1635))
- Fix dangling singleton pointer after deinit ([#&#8203;1638](godot-rust/gdext#1638))
- Fix RPC borrow panic for `call_local` ([#&#8203;1643](godot-rust/gdext#1643))

##### πŸ—οΈ Maintenance

- Add `once` flag to `defer_startup_warn!` and `defer_startup_error!` ([#&#8203;1613](godot-rust/gdext#1613))
- CI: unzip occasionally fails; retry ([#&#8203;1616](godot-rust/gdext#1616))
- Rename self-registration parts: `plugin` -> `shard` ([#&#8203;1618](godot-rust/gdext#1618))
- Replace internal `PassiveGd` with safer `BorrowedGd` ([#&#8203;1633](godot-rust/gdext#1633))

##### πŸ“š Documentation

- Document `register-docs` security; warn when used in export builds ([#&#8203;1615](godot-rust/gdext#1615))
- Document `#[class(tool)]` + `ready()` behavior across editor reload ([#&#8203;1614](godot-rust/gdext#1614))
- Fix borrow panic in `godot::task::spawn` doc example ([#&#8203;1622](godot-rust/gdext#1622))

</details>

<details>
<summary>serde-rs/serde (serde)</summary>

### [`v1.0.229`](https://github.com/serde-rs/serde/releases/tag/v1.0.229)

[Compare Source](serde-rs/serde@v1.0.228...v1.0.229)

- Update to syn 3

</details>

<details>
<summary>serde-rs/json (serde_json)</summary>

### [`v1.0.151`](https://github.com/serde-rs/json/releases/tag/v1.0.151)

[Compare Source](serde-rs/json@v1.0.150...v1.0.151)

- Add RawValue::from\_string\_unchecked ([#&#8203;1331](serde-rs/json#1331), thanks [@&#8203;WonderLawrence](https://github.com/WonderLawrence))

### [`v1.0.150`](https://github.com/serde-rs/json/releases/tag/v1.0.150)

[Compare Source](serde-rs/json@v1.0.149...v1.0.150)

- Reject non-string enum object keys ([#&#8203;1324](serde-rs/json#1324), thanks [@&#8203;puneetdixit200](https://github.com/puneetdixit200))

</details>

---

### Configuration

πŸ“… **Schedule**: (in timezone Asia/Taipei)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

β™» **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox.

πŸ‘» **Immortal**: This MR will be recreated if closed unmerged. Get [config help](https://github.com/renovatebot/renovate/discussions) if that's undesired.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box

---

This MR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4zMy4yIiwidXBkYXRlZEluVmVyIjoiNDQuMzMuMiIsInRhcmdldEJyYW5jaCI6Im1hc3RlciIsImxhYmVscyI6W119-->

See merge request TW0hank0/positive_mahjong!142
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c: register Register classes, functions and other symbols to GDScript feature Adds functionality to the library

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants