Skip to content

Commit 6e46fa4

Browse files
authored
Merge pull request #906 from godot-rust/feature/pass-by-ref-backend
Pass-by-ref for non-`Copy` builtins (backend)
2 parents b26e114 + d8264bd commit 6e46fa4

File tree

15 files changed

+315
-128
lines changed

15 files changed

+315
-128
lines changed

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

+6-5
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::builtin::*;
1212
use crate::meta::error::{ConvertError, FromGodotError, FromVariantError};
1313
use crate::meta::{
1414
ArrayElement, ArrayTypeInfo, FromGodot, GodotConvert, GodotFfiVariant, GodotType,
15-
PropertyHintInfo, ToGodot,
15+
PropertyHintInfo, RefArg, ToGodot,
1616
};
1717
use crate::registry::property::{Export, Var};
1818
use godot_ffi as sys;
@@ -1047,10 +1047,11 @@ impl<T: ArrayElement> Drop for Array<T> {
10471047
impl<T: ArrayElement> GodotType for Array<T> {
10481048
type Ffi = Self;
10491049

1050-
fn to_ffi(&self) -> Self::Ffi {
1051-
// SAFETY: we may pass type-transmuted arrays to FFI (e.g. Array<T> as Array<Variant>). This would fail the regular
1052-
// type-check in clone(), so we disable it. Type invariants are upheld by the "front-end" APIs.
1053-
unsafe { self.clone_unchecked() }
1050+
type ToFfi<'f> = RefArg<'f, Array<T>>
1051+
where Self: 'f;
1052+
1053+
fn to_ffi(&self) -> Self::ToFfi<'_> {
1054+
RefArg::new(self)
10541055
}
10551056

10561057
fn into_ffi(self) -> Self::Ffi {

godot-core/src/builtin/variant/impls.rs

+47-22
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ use super::*;
99
use crate::builtin::*;
1010
use crate::global;
1111
use crate::meta::error::{ConvertError, FromVariantError};
12-
use crate::meta::{ArrayElement, GodotFfiVariant, GodotType, PropertyHintInfo, PropertyInfo};
12+
use crate::meta::{
13+
ArrayElement, GodotFfiVariant, GodotType, PropertyHintInfo, PropertyInfo, RefArg,
14+
};
1315
use godot_ffi as sys;
1416
// For godot-cpp, see https://github.com/godotengine/godot-cpp/blob/master/include/godot_cpp/core/type_info.hpp.
1517

@@ -22,7 +24,15 @@ use godot_ffi as sys;
2224
//
2325
// Therefore, we can use `init` to indicate when it must be initialized in 4.0.
2426
macro_rules! impl_ffi_variant {
25-
($T:ty, $from_fn:ident, $to_fn:ident $(; $godot_type_name:ident)?) => {
27+
(ref $T:ty, $from_fn:ident, $to_fn:ident $(; $GodotTy:ident)?) => {
28+
impl_ffi_variant!(@impls by_ref; $T, $from_fn, $to_fn $(; $GodotTy)?);
29+
};
30+
($T:ty, $from_fn:ident, $to_fn:ident $(; $GodotTy:ident)?) => {
31+
impl_ffi_variant!(@impls by_val; $T, $from_fn, $to_fn $(; $GodotTy)?);
32+
};
33+
34+
// Implementations
35+
(@impls $by_ref_or_val:ident; $T:ty, $from_fn:ident, $to_fn:ident $(; $GodotTy:ident)?) => {
2636
impl GodotFfiVariant for $T {
2737
fn ffi_to_variant(&self) -> Variant {
2838
let variant = unsafe {
@@ -58,10 +68,7 @@ macro_rules! impl_ffi_variant {
5868

5969
impl GodotType for $T {
6070
type Ffi = Self;
61-
62-
fn to_ffi(&self) -> Self::Ffi {
63-
self.clone()
64-
}
71+
impl_ffi_variant!(@assoc_to_ffi $by_ref_or_val);
6572

6673
fn into_ffi(self) -> Self::Ffi {
6774
self
@@ -71,7 +78,7 @@ macro_rules! impl_ffi_variant {
7178
Ok(ffi)
7279
}
7380

74-
impl_ffi_variant!(@godot_type_name $T $(, $godot_type_name)?);
81+
impl_ffi_variant!(@godot_type_name $T $(, $GodotTy)?);
7582
}
7683

7784
impl ArrayElement for $T {}
@@ -88,6 +95,22 @@ macro_rules! impl_ffi_variant {
8895
stringify!($godot_type_name).into()
8996
}
9097
};
98+
99+
(@assoc_to_ffi by_ref) => {
100+
type ToFfi<'a> = RefArg<'a, Self>;
101+
102+
fn to_ffi(&self) -> Self::ToFfi<'_> {
103+
RefArg::new(self)
104+
}
105+
};
106+
107+
(@assoc_to_ffi by_val) => {
108+
type ToFfi<'a> = Self;
109+
110+
fn to_ffi(&self) -> Self::ToFfi<'_> {
111+
self.clone()
112+
}
113+
};
91114
}
92115

93116
// ----------------------------------------------------------------------------------------------------------------------------------------------
@@ -116,17 +139,17 @@ mod impls {
116139
impl_ffi_variant!(GString, string_to_variant, string_from_variant; String);
117140
impl_ffi_variant!(StringName, string_name_to_variant, string_name_from_variant);
118141
impl_ffi_variant!(NodePath, node_path_to_variant, node_path_from_variant);
119-
impl_ffi_variant!(PackedByteArray, packed_byte_array_to_variant, packed_byte_array_from_variant);
120-
impl_ffi_variant!(PackedInt32Array, packed_int32_array_to_variant, packed_int32_array_from_variant);
121-
impl_ffi_variant!(PackedInt64Array, packed_int64_array_to_variant, packed_int64_array_from_variant);
122-
impl_ffi_variant!(PackedFloat32Array, packed_float32_array_to_variant, packed_float32_array_from_variant);
123-
impl_ffi_variant!(PackedFloat64Array, packed_float64_array_to_variant, packed_float64_array_from_variant);
124-
impl_ffi_variant!(PackedStringArray, packed_string_array_to_variant, packed_string_array_from_variant);
125-
impl_ffi_variant!(PackedVector2Array, packed_vector2_array_to_variant, packed_vector2_array_from_variant);
126-
impl_ffi_variant!(PackedVector3Array, packed_vector3_array_to_variant, packed_vector3_array_from_variant);
142+
impl_ffi_variant!(ref PackedByteArray, packed_byte_array_to_variant, packed_byte_array_from_variant);
143+
impl_ffi_variant!(ref PackedInt32Array, packed_int32_array_to_variant, packed_int32_array_from_variant);
144+
impl_ffi_variant!(ref PackedInt64Array, packed_int64_array_to_variant, packed_int64_array_from_variant);
145+
impl_ffi_variant!(ref PackedFloat32Array, packed_float32_array_to_variant, packed_float32_array_from_variant);
146+
impl_ffi_variant!(ref PackedFloat64Array, packed_float64_array_to_variant, packed_float64_array_from_variant);
147+
impl_ffi_variant!(ref PackedStringArray, packed_string_array_to_variant, packed_string_array_from_variant);
148+
impl_ffi_variant!(ref PackedVector2Array, packed_vector2_array_to_variant, packed_vector2_array_from_variant);
149+
impl_ffi_variant!(ref PackedVector3Array, packed_vector3_array_to_variant, packed_vector3_array_from_variant);
127150
#[cfg(since_api = "4.3")]
128-
impl_ffi_variant!(PackedVector4Array, packed_vector4_array_to_variant, packed_vector4_array_from_variant);
129-
impl_ffi_variant!(PackedColorArray, packed_color_array_to_variant, packed_color_array_from_variant);
151+
impl_ffi_variant!(ref PackedVector4Array, packed_vector4_array_to_variant, packed_vector4_array_from_variant);
152+
impl_ffi_variant!(ref PackedColorArray, packed_color_array_to_variant, packed_color_array_from_variant);
130153
impl_ffi_variant!(Plane, plane_to_variant, plane_from_variant);
131154
impl_ffi_variant!(Projection, projection_to_variant, projection_from_variant);
132155
impl_ffi_variant!(Rid, rid_to_variant, rid_from_variant; RID);
@@ -135,7 +158,7 @@ mod impls {
135158
impl_ffi_variant!(Signal, signal_to_variant, signal_from_variant);
136159
impl_ffi_variant!(Transform2D, transform_2d_to_variant, transform_2d_from_variant);
137160
impl_ffi_variant!(Transform3D, transform_3d_to_variant, transform_3d_from_variant);
138-
impl_ffi_variant!(Dictionary, dictionary_to_variant, dictionary_from_variant);
161+
impl_ffi_variant!(ref Dictionary, dictionary_to_variant, dictionary_from_variant);
139162

140163
}
141164

@@ -162,9 +185,10 @@ impl GodotFfiVariant for () {
162185
}
163186

164187
impl GodotType for () {
165-
type Ffi = Self;
188+
type Ffi = ();
189+
type ToFfi<'a> = ();
166190

167-
fn to_ffi(&self) -> Self::Ffi {}
191+
fn to_ffi(&self) -> Self::ToFfi<'_> {}
168192

169193
fn into_ffi(self) -> Self::Ffi {}
170194

@@ -189,9 +213,10 @@ impl GodotFfiVariant for Variant {
189213

190214
impl GodotType for Variant {
191215
type Ffi = Variant;
216+
type ToFfi<'a> = RefArg<'a, Variant>;
192217

193-
fn to_ffi(&self) -> Self::Ffi {
194-
self.clone()
218+
fn to_ffi(&self) -> Self::ToFfi<'_> {
219+
RefArg::new(self)
195220
}
196221

197222
fn into_ffi(self) -> Self::Ffi {

godot-core/src/global/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,19 @@ use crate::obj::Gd;
4242
// Reminder: remove #![allow(deprecated)] in utilities.test along with the below functions.
4343

4444
#[deprecated = "Instance utilities in `godot::global` will be removed. Use methods on `Gd` and `InstanceId` instead.\n\
45-
For detailed reasons, see https://github.com/godot-rust/gdext/pull/892."]
45+
For detailed reasons, see https://github.com/godot-rust/gdext/pull/901."]
4646
pub fn instance_from_id(instance_id: i64) -> Option<Gd<crate::classes::Object>> {
4747
crate::gen::utilities::instance_from_id(instance_id)
4848
}
4949

5050
#[deprecated = "Instance utilities in `godot::global` will be removed. Use methods on `Gd` and `InstanceId` instead.\n\
51-
For detailed reasons, see https://github.com/godot-rust/gdext/pull/892."]
51+
For detailed reasons, see https://github.com/godot-rust/gdext/pull/901."]
5252
pub fn is_instance_valid(instance: Variant) -> bool {
5353
crate::gen::utilities::is_instance_valid(&instance)
5454
}
5555

5656
#[deprecated = "Instance utilities in `godot::global` will be removed. Use methods on `Gd` and `InstanceId` instead.\n\
57-
For detailed reasons, see https://github.com/godot-rust/gdext/pull/892."]
57+
For detailed reasons, see https://github.com/godot-rust/gdext/pull/901."]
5858
pub fn is_instance_id_valid(instance_id: i64) -> bool {
5959
crate::gen::utilities::is_instance_id_valid(instance_id)
6060
}

godot-core/src/meta/godot_convert/impls.rs

+15-5
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,13 @@ impl<T> GodotType for Option<T>
2525
where
2626
T: GodotType,
2727
T::Ffi: GodotNullableFfi,
28+
for<'f> T::ToFfi<'f>: GodotNullableFfi,
2829
{
2930
type Ffi = T::Ffi;
3031

31-
fn to_ffi(&self) -> Self::Ffi {
32+
type ToFfi<'f> = T::ToFfi<'f>;
33+
34+
fn to_ffi(&self) -> Self::ToFfi<'_> {
3235
GodotNullableFfi::flatten_option(self.as_ref().map(|t| t.to_ffi()))
3336
}
3437

@@ -91,7 +94,11 @@ where
9194
impl<T: ToGodot> ToGodot for Option<T>
9295
where
9396
Option<T::Via>: GodotType,
94-
for<'f> T::ToVia<'f>: GodotType<Ffi: GodotNullableFfi>,
97+
for<'v, 'f> T::ToVia<'v>: GodotType<
98+
// Associated types need to be nullable.
99+
Ffi: GodotNullableFfi,
100+
ToFfi<'f>: GodotNullableFfi,
101+
>,
95102
{
96103
type ToVia<'v> = Option<T::ToVia<'v>>
97104
// type ToVia<'v> = Self::Via
@@ -155,8 +162,9 @@ macro_rules! impl_godot_scalar {
155162
($T:ty as $Via:ty, $err:path, $param_metadata:expr) => {
156163
impl GodotType for $T {
157164
type Ffi = $Via;
165+
type ToFfi<'f> = $Via;
158166

159-
fn to_ffi(&self) -> Self::Ffi {
167+
fn to_ffi(&self) -> Self::ToFfi<'_> {
160168
(*self).into()
161169
}
162170

@@ -188,8 +196,9 @@ macro_rules! impl_godot_scalar {
188196
($T:ty as $Via:ty, $param_metadata:expr; lossy) => {
189197
impl GodotType for $T {
190198
type Ffi = $Via;
199+
type ToFfi<'f> = $Via;
191200

192-
fn to_ffi(&self) -> Self::Ffi {
201+
fn to_ffi(&self) -> Self::ToFfi<'_> {
193202
*self as $Via
194203
}
195204

@@ -289,8 +298,9 @@ impl_godot_scalar!(
289298

290299
impl GodotType for u64 {
291300
type Ffi = i64;
301+
type ToFfi<'f> = i64;
292302

293-
fn to_ffi(&self) -> Self::Ffi {
303+
fn to_ffi(&self) -> Self::ToFfi<'_> {
294304
*self as i64
295305
}
296306

godot-core/src/meta/godot_convert/mod.rs

+4-9
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ pub trait GodotConvert {
4040
///
4141
/// Please read the [`godot::meta` module docs][crate::meta] for further information about conversions.
4242
pub trait ToGodot: Sized + GodotConvert {
43+
/// Target type of [`to_godot()`](ToGodot::to_godot), which differs from [`Via`](GodotConvert::Via) for pass-by-reference types.
4344
type ToVia<'v>: GodotType
4445
where
4546
Self: 'v;
@@ -95,16 +96,10 @@ pub trait FromGodot: Sized + GodotConvert {
9596
}
9697
}
9798

98-
// Note: removing the implicit lifetime (by taking value: T instead of &T) causes issues due to allegedly returning a lifetime
99-
// to a local variable, even though the result Ffi is 'static by definition.
100-
#[allow(clippy::needless_lifetimes)] // eliding causes error: missing generics for associated type `godot_convert::ToGodot::ToVia`
101-
pub(crate) fn into_ffi<'v, T: ToGodot>(value: &'v T) -> <T::ToVia<'v> as GodotType>::Ffi {
102-
let by_ref = value.to_godot();
103-
by_ref.to_ffi()
104-
}
105-
10699
pub(crate) fn into_ffi_variant<T: ToGodot>(value: &T) -> Variant {
107-
GodotFfiVariant::ffi_to_variant(&into_ffi(value))
100+
let via = value.to_godot();
101+
let ffi = via.to_ffi();
102+
GodotFfiVariant::ffi_to_variant(&ffi)
108103
}
109104

110105
pub(crate) fn try_from_ffi<T: FromGodot>(

0 commit comments

Comments
 (0)