Skip to content

Commit f339323

Browse files
committed
Add OnEditor<T>, remove Export implementations for DynGd and Gd
- Clean up `OnEditor<...>` bounds. - Make `DynGd<T: Inherits<Resource>, D>` exportable with `Option` & `DynGd` - Fix export for `DynGd<T: Inherits<Resource> + Bounds<Declarer = bounds::DeclUser>, D>` - Code tweaks according to CR
1 parent cdcdadc commit f339323

File tree

7 files changed

+29
-64
lines changed

7 files changed

+29
-64
lines changed

godot-core/src/builtin/collections/array.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1102,9 +1102,9 @@ where
11021102

11031103
impl<T: ArrayElement> BuiltinExport for Array<T> {}
11041104

1105-
impl<T: GodotClass> Export for Array<Gd<T>>
1105+
impl<T> Export for Array<Gd<T>>
11061106
where
1107-
T: Bounds<Exportable = bounds::Yes>,
1107+
T: GodotClass + Bounds<Exportable = bounds::Yes>,
11081108
{
11091109
fn export_hint() -> PropertyHintInfo {
11101110
PropertyHintInfo::export_array_element::<Gd<T>>()
@@ -1121,7 +1121,7 @@ where
11211121
/// Consider exporting `Array<Gd<T>>` instead of `Array<DynGd<T, D>>` for user-declared GDExtension classes.
11221122
impl<T: GodotClass, D> Export for Array<DynGd<T, D>>
11231123
where
1124-
T: GodotClass + Bounds<Exportable = bounds::Yes, Declarer = bounds::DeclEngine>,
1124+
T: GodotClass + Bounds<Exportable = bounds::Yes>,
11251125
D: ?Sized + 'static,
11261126
{
11271127
fn export_hint() -> PropertyHintInfo {

godot-core/src/obj/dyn_gd.rs

+8-47
Original file line numberDiff line numberDiff line change
@@ -142,48 +142,9 @@ use std::{fmt, ops};
142142
/// Exporting `DynGd<T, D>` is possible only via [`OnEditor`] or [`Option`].
143143
/// `DynGd<T, D>` can also be exported directly as an element of an array such as `Array<DynGd<T, D>>`.
144144
///
145-
/// Since `DynGd<T, D>` expresses shared functionality `D` among classes inheriting `T`,
146-
/// `#[export]` for `DynGd<T, D>` where `T` is a concrete Rust class is not allowed.
147-
///
148-
/// ```compile_fail
149-
///
150-
/// use godot::prelude::*;
151-
///
152-
/// trait Health { /* ... */ }
153-
///
154-
/// #[derive(GodotClass)]
155-
/// # #[class(init)]
156-
/// struct Monster { /* ... */ }
157-
///
158-
/// #[godot_dyn]
159-
/// impl Health for Monster { /* ... */ }
160-
///
161-
/// #[derive(GodotClass)]
162-
/// #[class(init, base = Node)]
163-
/// struct MyClass {
164-
/// #[export]
165-
/// dyn_concrete: Option<DynGd<Monster, dyn Health>>,
166-
/// }
167-
/// ```
168-
///
169-
/// Consider using `Gd<T>` instead in such cases:
170-
///
171-
/// ```
172-
/// use godot::prelude::*;
173-
///
174-
/// #[derive(GodotClass)]
175-
/// #[class(init, base = Node)]
176-
/// struct Monster { /* ... */ }
177-
///
178-
/// /* ... */
179-
///
180-
/// #[derive(GodotClass)]
181-
/// #[class(init, base = Node)]
182-
/// struct MyClass {
183-
/// #[export]
184-
/// dyn_concrete: Option<Gd<Monster>>,
185-
/// }
186-
/// ```
145+
/// Since `DynGd<T, D>` represents shared functionality `D` across classes inheriting from `T`,
146+
/// consider using `#[export] Gd<T>` instead of `#[export] DynGd<T, D>`
147+
/// in cases when `T` is a concrete Rust `GodotClass`.
187148
///
188149
/// ## Node based classes
189150
///
@@ -562,7 +523,7 @@ where
562523
/// Consider exporting `Option<Gd<T>>` instead of `Option<DynGd<T, D>>` for user-declared GDExtension classes.
563524
impl<T, D> Export for Option<DynGd<T, D>>
564525
where
565-
T: GodotClass + Bounds<Exportable = bounds::Yes, Declarer = bounds::DeclEngine>,
526+
T: GodotClass + Bounds<Exportable = bounds::Yes>,
566527
D: ?Sized + 'static,
567528
{
568529
fn export_hint() -> PropertyHintInfo {
@@ -599,12 +560,12 @@ where
599560
D: ?Sized + 'static,
600561
{
601562
fn get_property(&self) -> Self::Via {
602-
OnEditor::<DynGd<T, D>>::get_property_inner(self)
563+
Self::get_property_inner(self)
603564
}
604565

605566
fn set_property(&mut self, value: Self::Via) {
606567
// `set_property` can't be delegated to Gd<T>, since we have to set `erased_obj` as well.
607-
OnEditor::<DynGd<T, D>>::set_property_inner(self, value)
568+
Self::set_property_inner(self, value)
608569
}
609570
}
610571

@@ -613,8 +574,8 @@ where
613574
/// Consider exporting `OnEditor<Gd<T>>` instead of `OnEditor<DynGd<T, D>>` for user-declared GDExtension classes.
614575
impl<T, D> Export for OnEditor<DynGd<T, D>>
615576
where
616-
OnEditor<DynGd<T, D>>: Var,
617-
T: GodotClass + Bounds<Exportable = bounds::Yes, Declarer = bounds::DeclEngine>,
577+
Self: Var,
578+
T: GodotClass + Bounds<Exportable = bounds::Yes>,
618579
D: ?Sized + 'static,
619580
{
620581
fn export_hint() -> PropertyHintInfo {

godot-core/src/obj/gd.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -937,21 +937,20 @@ where
937937
impl<T> Var for OnEditor<Gd<T>>
938938
where
939939
T: GodotClass,
940-
OnEditor<Gd<T>>: GodotConvert<Via = Option<<Gd<T> as GodotConvert>::Via>>,
941940
{
942941
fn get_property(&self) -> Self::Via {
943-
OnEditor::<Gd<T>>::get_property_inner(self)
942+
Self::get_property_inner(self)
944943
}
945944

946945
fn set_property(&mut self, value: Self::Via) {
947-
OnEditor::<Gd<T>>::set_property_inner(self, value)
946+
Self::set_property_inner(self, value)
948947
}
949948
}
950949

951950
impl<T> Export for OnEditor<Gd<T>>
952951
where
952+
Self: Var,
953953
T: GodotClass + Bounds<Exportable = bounds::Yes>,
954-
OnEditor<Gd<T>>: Var,
955954
{
956955
fn export_hint() -> PropertyHintInfo {
957956
PropertyHintInfo::export_gd::<T>()

godot-core/src/obj/oneditor.rs

+3
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ pub(crate) enum OnEditorState<T> {
166166
Initialized(T),
167167
}
168168

169+
/// `OnEditor<T>` is usable only for properties – which is enforced via `Var` and `FromGodot` bounds.
170+
///
171+
/// Furthermore, `PartialEq` is needed to compare against uninitialized sentinel values.
169172
impl<T: Var + FromGodot + PartialEq> OnEditor<T> {
170173
/// Initializes invalid `OnEditor<T>` with given value.
171174
///

godot-core/src/registry/class.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -370,10 +370,12 @@ where
370370
// For example – don't include Nodes or Objects while creating hint_string for Resource.
371371
let relations_iter = relations.iter().filter_map(|implementor| {
372372
// TODO – check if caching it (using is_derived_base_cached) yields any benefits.
373-
if ClassDb::singleton().is_parent_class(
374-
&implementor.parent_class_name?.to_string_name(),
375-
&T::class_name().to_string_name(),
376-
) {
373+
if implementor.parent_class_name? == T::class_name()
374+
|| ClassDb::singleton().is_parent_class(
375+
&implementor.parent_class_name?.to_string_name(),
376+
&T::class_name().to_string_name(),
377+
)
378+
{
377379
Some(implementor)
378380
} else {
379381
None

itest/godot/ManualFfiTests.gd

+3-3
Original file line numberDiff line numberDiff line change
@@ -309,19 +309,19 @@ func test_option_export():
309309
assert_eq(obj.optional_export, null)
310310

311311
var test_node := Node.new()
312+
var test_resource := Resource.new()
312313

313314
obj.optional = test_node
314-
obj.optional_export = test_node
315+
obj.optional_export = test_resource
315316
assert_eq(obj.optional, test_node)
316-
assert_eq(obj.optional_export, test_node)
317+
assert_eq(obj.optional_export, test_resource)
317318

318319
obj.optional = null
319320
obj.optional_export = null
320321
assert_eq(obj.optional, null)
321322
assert_eq(obj.optional_export, null)
322323

323324
test_node.free()
324-
obj.free()
325325

326326
func test_func_rename():
327327
var func_rename := FuncObj.new()

itest/rust/src/register_tests/option_ffi_test.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
66
*/
77

8-
use godot::classes::{Node, Object, RefCounted};
8+
use godot::classes::{Node, Object, RefCounted, Resource};
99
use godot::meta::GodotType;
1010
use godot::obj::{Gd, NewAlloc, NewGd, RawGd};
1111
use godot::register::{godot_api, GodotClass};
@@ -97,11 +97,11 @@ impl OptionFfiTest {
9797
}
9898

9999
#[derive(GodotClass)]
100-
#[class(init, base=Node)]
100+
#[class(init)]
101101
struct OptionExportFfiTest {
102102
#[var]
103103
optional: Option<Gd<Node>>,
104104

105105
#[export]
106-
optional_export: Option<Gd<Node>>,
106+
optional_export: Option<Gd<Resource>>,
107107
}

0 commit comments

Comments
 (0)