Skip to content

Commit eb30a8b

Browse files
bors[bot]ttencate
andauthored
Merge #198
198: Add an Export trait to use in autogenerated getters r=Bromeon a=ttencate Fixes #197. Note that some types are still not supported, since they're not implemented yet in gdext: `Aabb`, `Plane`, `Rect2` and `Rect2i`. `Signal` and `Callable` don't implement `Export` either. Probably it makes no sense for `Signal`, and should eventually be supported for `Callable`. Co-authored-by: Thomas ten Cate <[email protected]>
2 parents dbce0d9 + d52c826 commit eb30a8b

File tree

9 files changed

+109
-13
lines changed

9 files changed

+109
-13
lines changed

godot-core/src/builtin/array.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use godot_ffi as sys;
88

99
use crate::builtin::meta::VariantMetadata;
1010
use crate::builtin::*;
11-
use crate::obj::Share;
11+
use crate::obj::{Export, Share};
1212
use std::fmt;
1313
use std::marker::PhantomData;
1414
use sys::{ffi_methods, interface_fn, GodotFfi};
@@ -601,6 +601,12 @@ impl<T: VariantMetadata> Share for Array<T> {
601601
}
602602
}
603603

604+
impl<T: VariantMetadata> Export for Array<T> {
605+
fn export(&self) -> Self {
606+
self.share()
607+
}
608+
}
609+
604610
impl<T: VariantMetadata> Default for Array<T> {
605611
#[inline]
606612
fn default() -> Self {

godot-core/src/builtin/dictionary.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use godot_ffi as sys;
88

99
use crate::builtin::{inner, FromVariant, ToVariant, Variant};
10-
use crate::obj::Share;
10+
use crate::obj::{Export, Share};
1111
use std::fmt;
1212
use std::marker::PhantomData;
1313
use std::ptr::addr_of_mut;
@@ -280,6 +280,12 @@ impl Share for Dictionary {
280280
}
281281
}
282282

283+
impl Export for Dictionary {
284+
fn export(&self) -> Self {
285+
self.share()
286+
}
287+
}
288+
283289
// ----------------------------------------------------------------------------------------------------------------------------------------------
284290
// Conversion traits
285291

godot-core/src/builtin/mod.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,3 +318,70 @@ macro_rules! real {
318318
f
319319
}};
320320
}
321+
322+
// ----------------------------------------------------------------------------------------------------------------------------------------------
323+
324+
/// Implementations of the `Export` trait for types where it can be done trivially.
325+
mod export {
326+
use crate::builtin::*;
327+
use crate::obj::Export;
328+
329+
macro_rules! impl_export_by_clone {
330+
($ty:path) => {
331+
impl Export for $ty {
332+
fn export(&self) -> Self {
333+
// If `Self` does not implement `Clone`, this gives a clearer error message
334+
// than simply `self.clone()`.
335+
Clone::clone(self)
336+
}
337+
}
338+
};
339+
}
340+
341+
impl_export_by_clone!(bool);
342+
impl_export_by_clone!(isize);
343+
impl_export_by_clone!(usize);
344+
impl_export_by_clone!(i8);
345+
impl_export_by_clone!(i16);
346+
impl_export_by_clone!(i32);
347+
impl_export_by_clone!(i64);
348+
impl_export_by_clone!(u8);
349+
impl_export_by_clone!(u16);
350+
impl_export_by_clone!(u32);
351+
impl_export_by_clone!(u64);
352+
impl_export_by_clone!(f32);
353+
impl_export_by_clone!(f64);
354+
355+
// impl_export_by_clone!(Aabb); // TODO uncomment once Aabb implements Clone
356+
impl_export_by_clone!(Basis);
357+
impl_export_by_clone!(Color);
358+
impl_export_by_clone!(GodotString);
359+
impl_export_by_clone!(NodePath);
360+
impl_export_by_clone!(PackedByteArray);
361+
impl_export_by_clone!(PackedColorArray);
362+
impl_export_by_clone!(PackedFloat32Array);
363+
impl_export_by_clone!(PackedFloat64Array);
364+
impl_export_by_clone!(PackedInt32Array);
365+
impl_export_by_clone!(PackedInt64Array);
366+
impl_export_by_clone!(PackedStringArray);
367+
impl_export_by_clone!(PackedVector2Array);
368+
impl_export_by_clone!(PackedVector3Array);
369+
// impl_export_by_clone!(Plane); // TODO uncomment once Plane implements Clone
370+
impl_export_by_clone!(Projection);
371+
impl_export_by_clone!(Quaternion);
372+
// impl_export_by_clone!(Rect2); // TODO uncomment once Rect2 implements Clone
373+
// impl_export_by_clone!(Rect2i); // TODO uncomment once Rect2i implements Clone
374+
impl_export_by_clone!(Rid);
375+
impl_export_by_clone!(StringName);
376+
impl_export_by_clone!(Transform2D);
377+
impl_export_by_clone!(Transform3D);
378+
impl_export_by_clone!(Vector2);
379+
impl_export_by_clone!(Vector2i);
380+
impl_export_by_clone!(Vector3);
381+
impl_export_by_clone!(Vector3i);
382+
impl_export_by_clone!(Vector4);
383+
384+
// TODO investigate whether these should impl Export at all, and if so, how
385+
// impl_export_by_clone!(Callable);
386+
// impl_export_by_clone!(Signal);
387+
}

godot-core/src/obj/gd.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::builtin::meta::{ClassName, VariantMetadata};
1818
use crate::builtin::{FromVariant, ToVariant, Variant, VariantConversionError};
1919
use crate::obj::dom::Domain as _;
2020
use crate::obj::mem::Memory as _;
21-
use crate::obj::{cap, dom, mem, GodotClass, Inherits, Share};
21+
use crate::obj::{cap, dom, mem, Export, GodotClass, Inherits, Share};
2222
use crate::obj::{GdMut, GdRef, InstanceId};
2323
use crate::storage::InstanceStorage;
2424
use crate::{callbacks, engine, out};
@@ -588,6 +588,12 @@ impl<T: GodotClass> Share for Gd<T> {
588588
}
589589
}
590590

591+
impl<T: GodotClass> Export for Gd<T> {
592+
fn export(&self) -> Self {
593+
self.share()
594+
}
595+
}
596+
591597
// ----------------------------------------------------------------------------------------------------------------------------------------------
592598
// Trait impls
593599

godot-core/src/obj/traits.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ pub trait Share {
5252
fn share(&self) -> Self;
5353
}
5454

55+
/// Trait implemented for types that can be used as `#[export]` fields. This creates a copy of the
56+
/// value, for some type-specific definition of "copy". For example, `Array` and `Gd` are returned
57+
/// via `Share::share()` instead of copying the actual data.
58+
pub trait Export {
59+
/// Creates a copy to be returned from a getter.
60+
fn export(&self) -> Self;
61+
}
62+
5563
/// Non-strict inheritance relationship in the Godot class hierarchy.
5664
///
5765
/// `Derived: Inherits<Base>` means that either `Derived` is a subclass of `Base`, or the class `Base` itself (hence "non-strict").

godot-macros/src/derive_godot_class.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ fn make_exports_impl(class_name: &Ident, fields: &Fields) -> TokenStream {
332332
};
333333
getter_setter_impls.push(quote! {
334334
pub #signature {
335-
self.#field_ident
335+
::godot::obj::Export::export(&self.#field_ident)
336336
}
337337
});
338338
export_tokens.push(quote! {

godot/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ pub mod prelude {
136136
};
137137
pub use super::init::{gdextension, ExtensionLayer, ExtensionLibrary, InitHandle, InitLevel};
138138
pub use super::log::*;
139-
pub use super::obj::{Base, Gd, GdMut, GdRef, GodotClass, Inherits, InstanceId, Share};
139+
pub use super::obj::{Base, Export, Gd, GdMut, GdRef, GodotClass, Inherits, InstanceId, Share};
140140

141141
// Make trait methods available
142142
pub use super::engine::NodeExt as _;

itest/godot/ManualFfiTests.gd

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,10 @@ func test_export():
5555
assert_eq(obj.object_val, node)
5656

5757
var texture_val_meta = obj.get_property_list().filter(
58-
func(el): return el["name"] == "texture_val"
58+
func(el): return el["name"] == "texture_val_rw"
5959
).front()
6060

61-
assert_that(texture_val_meta != null, "'texture_val' is defined")
61+
assert_that(texture_val_meta != null, "'texture_val_rw' is defined")
6262
assert_eq(texture_val_meta["hint"], PropertyHint.PROPERTY_HINT_RESOURCE_TYPE)
6363
assert_eq(texture_val_meta["hint_string"], "Texture")
6464

itest/rust/src/export_test.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@ struct HasProperty {
3131
string_val: GodotString,
3232
#[export(get = "get_object_val", set = "set_object_val")]
3333
object_val: Option<Gd<Object>>,
34+
#[export]
35+
texture_val: Gd<Texture>,
3436
#[export(get = "get_texture_val", set = "set_texture_val", hint = PROPERTY_HINT_RESOURCE_TYPE, hint_desc = "Texture")]
35-
texture_val: Option<Gd<Texture>>,
37+
texture_val_rw: Option<Gd<Texture>>,
3638
}
3739

3840
#[godot_api]
@@ -98,17 +100,17 @@ impl HasProperty {
98100
}
99101

100102
#[func]
101-
pub fn get_texture_val(&self) -> Variant {
102-
if let Some(texture_val) = self.texture_val.as_ref() {
103+
pub fn get_texture_val_rw(&self) -> Variant {
104+
if let Some(texture_val) = self.texture_val_rw.as_ref() {
103105
texture_val.to_variant()
104106
} else {
105107
Variant::nil()
106108
}
107109
}
108110

109111
#[func]
110-
pub fn set_texture_val(&mut self, val: Gd<Texture>) {
111-
self.texture_val = Some(val);
112+
pub fn set_texture_val_rw(&mut self, val: Gd<Texture>) {
113+
self.texture_val_rw = Some(val);
112114
}
113115
}
114116

@@ -124,7 +126,8 @@ impl NodeVirtual for HasProperty {
124126
int_val_setter: 0,
125127
object_val: None,
126128
string_val: GodotString::new(),
127-
texture_val: None,
129+
texture_val: Texture::new(),
130+
texture_val_rw: None,
128131
base,
129132
}
130133
}

0 commit comments

Comments
 (0)