Skip to content

Commit 585076e

Browse files
committed
Add GodotFfi::from_sys_init_default(), which can call Default::default() before running the init fn
Impacts: * Simplifies ffi_methods! usage for Variant, GodotString, StringName, TypedArray, PackedArray, Dictionary * impl Default does not need to re-implement from_sys_init() * Functions which do *not* expect a pre-initialized instance can directly call from_sys_init() in the future, avoiding 2 inits (memory leak)
1 parent de9d913 commit 585076e

File tree

14 files changed

+96
-135
lines changed

14 files changed

+96
-135
lines changed

godot-codegen/src/class_generator.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,7 @@ impl VariantFfi {
686686
fn type_ptr() -> Self {
687687
Self {
688688
sys_method: ident("sys_const"),
689-
from_sys_init_method: ident("from_sys_init"),
689+
from_sys_init_method: ident("from_sys_init_default"),
690690
}
691691
}
692692
}
@@ -876,7 +876,7 @@ fn make_return(
876876
}
877877
(None, Some(return_ty)) => {
878878
quote! {
879-
<#return_ty as sys::GodotFfi>::from_sys_init(|return_ptr| {
879+
<#return_ty as sys::GodotFfi>::from_sys_init_default(|return_ptr| {
880880
#ptrcall_invocation
881881
})
882882
}

godot-core/src/builtin/array.rs

Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,11 @@ impl_builtin_froms!(Array;
7070

7171
impl<T: VariantMetadata> TypedArray<T> {
7272
fn from_opaque(opaque: sys::types::OpaqueArray) -> Self {
73-
let array = Self {
73+
// Note: type is not yet checked at this point, because array has not yet been initialized!
74+
Self {
7475
opaque,
7576
_phantom: PhantomData,
76-
};
77-
array.check_type();
78-
array
77+
}
7978
}
8079

8180
/// Returns the number of elements in the array. Equivalent of `size()` in Godot.
@@ -320,8 +319,9 @@ impl<T: VariantMetadata> TypedArray<T> {
320319
/// # Panics
321320
///
322321
/// If the inner type doesn't match `T` or no type is set at all.
323-
fn check_type(&self) {
322+
fn with_checked_type(self) -> Self {
324323
assert_eq!(self.type_info(), TypeInfo::new::<T>());
324+
self
325325
}
326326

327327
/// Sets the type of the inner array. Can only be called once, directly after creation.
@@ -567,17 +567,9 @@ impl<T: VariantMetadata + ToVariant> TypedArray<T> {
567567
// }
568568

569569
impl<T: VariantMetadata> GodotFfi for TypedArray<T> {
570-
ffi_methods! {
571-
type sys::GDExtensionTypePtr = *mut Opaque;
572-
fn from_sys;
573-
fn sys;
574-
fn write_sys;
575-
}
576-
577-
unsafe fn from_sys_init(init_fn: impl FnOnce(sys::GDExtensionTypePtr)) -> Self {
578-
// Can't use uninitialized pointer -- Array CoW implementation in C++ expects that on
579-
// assignment, the target CoW pointer is either initialized or nullptr
570+
ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque; .. }
580571

572+
unsafe fn from_sys_init_default(init_fn: impl FnOnce(sys::GDExtensionTypePtr)) -> Self {
581573
let mut result = Self::default();
582574
init_fn(result.sys_mut());
583575
result
@@ -598,28 +590,25 @@ impl<T: VariantMetadata> fmt::Debug for TypedArray<T> {
598590
/// [`Array::duplicate_deep()`].
599591
impl<T: VariantMetadata> Share for TypedArray<T> {
600592
fn share(&self) -> Self {
601-
unsafe {
602-
Self::from_sys_init(|self_ptr| {
593+
let array = unsafe {
594+
Self::from_sys_init_default(|self_ptr| {
603595
let ctor = ::godot_ffi::builtin_fn!(array_construct_copy);
604596
let args = [self.sys_const()];
605597
ctor(self_ptr, args.as_ptr());
606598
})
607-
}
599+
};
600+
array.with_checked_type()
608601
}
609602
}
610603

611604
impl<T: VariantMetadata> Default for TypedArray<T> {
612605
#[inline]
613606
fn default() -> Self {
614-
// Note: can't use from_sys_init(), as that calls the default constructor
615-
// (because most assignments expect initialized target type)
616-
let mut uninit = std::mem::MaybeUninit::<TypedArray<T>>::uninit();
617607
let mut array = unsafe {
618-
let self_ptr = (*uninit.as_mut_ptr()).sys_mut();
619-
sys::builtin_call! {
620-
array_construct_default(self_ptr, std::ptr::null_mut())
621-
};
622-
uninit.assume_init()
608+
Self::from_sys_init(|self_ptr| {
609+
let ctor = ::godot_ffi::builtin_fn!(array_construct_default);
610+
ctor(self_ptr, std::ptr::null_mut())
611+
})
623612
};
624613
array.init_inner_type();
625614
array
@@ -661,14 +650,14 @@ impl<T: VariantMetadata> FromVariant for TypedArray<T> {
661650
if variant.get_type() != Self::variant_type() {
662651
return Err(VariantConversionError);
663652
}
664-
let result = unsafe {
665-
Self::from_sys_init(|self_ptr| {
653+
let array = unsafe {
654+
Self::from_sys_init_default(|self_ptr| {
666655
let array_from_variant = sys::builtin_fn!(array_from_variant);
667656
array_from_variant(self_ptr, variant.var_sys());
668657
})
669658
};
670659

671-
Ok(result)
660+
Ok(array.with_checked_type())
672661
}
673662
}
674663

@@ -773,7 +762,7 @@ impl<T: VariantMetadata> PartialEq for TypedArray<T> {
773762
let mut result = false;
774763
sys::builtin_call! {
775764
array_operator_equal(self.sys(), other.sys(), result.sys_mut())
776-
};
765+
}
777766
result
778767
}
779768
}

godot-core/src/builtin/dictionary.rs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -240,17 +240,9 @@ impl Dictionary {
240240
// Traits
241241

242242
impl GodotFfi for Dictionary {
243-
ffi_methods! {
244-
type sys::GDExtensionTypePtr = *mut Opaque;
245-
fn from_sys;
246-
fn sys;
247-
fn write_sys;
248-
}
249-
250-
unsafe fn from_sys_init(init_fn: impl FnOnce(sys::GDExtensionTypePtr)) -> Self {
251-
// Can't use uninitialized pointer -- Dictionary CoW implementation in C++ expects that on
252-
// assignment, the target CoW pointer is either initialized or nullptr
243+
ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque; .. }
253244

245+
unsafe fn from_sys_init_default(init_fn: impl FnOnce(sys::GDExtensionTypePtr)) -> Self {
254246
let mut result = Self::default();
255247
init_fn(result.sys_mut());
256248
result
@@ -279,7 +271,7 @@ impl fmt::Debug for Dictionary {
279271
impl Share for Dictionary {
280272
fn share(&self) -> Self {
281273
unsafe {
282-
Self::from_sys_init(|self_ptr| {
274+
Self::from_sys_init_default(|self_ptr| {
283275
let ctor = sys::builtin_fn!(dictionary_construct_copy);
284276
let args = [self.sys_const()];
285277
ctor(self_ptr, args.as_ptr());

godot-core/src/builtin/macros.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ macro_rules! impl_builtin_traits_inner {
3333
#[inline]
3434
fn clone(&self) -> Self {
3535
unsafe {
36-
Self::from_sys_init(|self_ptr| {
36+
Self::from_sys_init_default(|self_ptr| {
3737
let ctor = ::godot_ffi::builtin_fn!($gd_method);
3838
let args = [self.sys_const()];
3939
ctor(self_ptr, args.as_ptr());
@@ -116,7 +116,7 @@ macro_rules! impl_builtin_traits_inner {
116116
return Err($crate::builtin::variant::VariantConversionError)
117117
}
118118
let result = unsafe {
119-
Self::from_sys_init(|self_ptr| {
119+
Self::from_sys_init_default(|self_ptr| {
120120
let converter = sys::builtin_fn!($gd_method);
121121
converter(self_ptr, variant.var_sys());
122122
})
@@ -168,7 +168,7 @@ macro_rules! impl_builtin_froms {
168168
$(impl From<&$From> for $To {
169169
fn from(other: &$From) -> Self {
170170
unsafe {
171-
Self::from_sys_init(|ptr| {
171+
Self::from_sys_init_default(|ptr| {
172172
let args = [other.sys_const()];
173173
::godot_ffi::builtin_call! {
174174
$from_fn(ptr, args.as_ptr())

godot-core/src/builtin/node_path.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
use crate::builtin::GodotString;
88
use godot_ffi as sys;
9-
use godot_ffi::{ffi_methods, GodotFfi};
9+
use godot_ffi::{ffi_methods, GDExtensionTypePtr, GodotFfi};
1010
use std::fmt::{Display, Formatter, Result as FmtResult};
1111

1212
pub struct NodePath {
@@ -21,12 +21,18 @@ impl NodePath {
2121

2222
impl GodotFfi for NodePath {
2323
ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque; .. }
24+
25+
unsafe fn from_sys_init_default(init_fn: impl FnOnce(GDExtensionTypePtr)) -> Self {
26+
let mut result = Self::default();
27+
init_fn(result.sys_mut());
28+
result
29+
}
2430
}
2531

2632
impl From<&GodotString> for NodePath {
2733
fn from(path: &GodotString) -> Self {
2834
unsafe {
29-
Self::from_sys_init(|self_ptr| {
35+
Self::from_sys_init_default(|self_ptr| {
3036
let ctor = sys::builtin_fn!(node_path_from_string);
3137
let args = [path.sys_const()];
3238
ctor(self_ptr, args.as_ptr());
@@ -38,7 +44,7 @@ impl From<&GodotString> for NodePath {
3844
impl From<&NodePath> for GodotString {
3945
fn from(path: &NodePath) -> Self {
4046
unsafe {
41-
Self::from_sys_init(|self_ptr| {
47+
Self::from_sys_init_default(|self_ptr| {
4248
let ctor = sys::builtin_fn!(string_from_node_path);
4349
let args = [path.sys_const()];
4450
ctor(self_ptr, args.as_ptr());

godot-core/src/builtin/others.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ impl Callable {
5050
// upcast not needed
5151
let method = method.into();
5252
unsafe {
53-
Self::from_sys_init(|self_ptr| {
53+
Self::from_sys_init_default(|self_ptr| {
5454
let ctor = sys::builtin_fn!(callable_from_object_method);
5555
let args = [object.sys_const(), method.sys_const()];
5656
ctor(self_ptr, args.as_ptr());
@@ -66,6 +66,7 @@ impl Callable {
6666

6767
impl_builtin_traits! {
6868
for Callable {
69+
// Default => callable_construct_default;
6970
FromVariant => callable_from_variant;
7071
}
7172
}

godot-core/src/builtin/packed_array.rs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -386,17 +386,9 @@ macro_rules! impl_packed_array {
386386
}
387387

388388
impl GodotFfi for $PackedArray {
389-
ffi_methods! {
390-
type sys::GDExtensionTypePtr = *mut Opaque;
391-
fn from_sys;
392-
fn sys;
393-
fn write_sys;
394-
}
395-
396-
unsafe fn from_sys_init(init_fn: impl FnOnce(sys::GDExtensionTypePtr)) -> Self {
397-
// Can't use uninitialized pointer -- Vector CoW implementation in C++ expects that
398-
// on assignment, the target CoW pointer is either initialized or nullptr
389+
ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque; .. }
399390

391+
unsafe fn from_sys_init_default(init_fn: impl FnOnce(sys::GDExtensionTypePtr)) -> Self {
400392
let mut result = Self::default();
401393
init_fn(result.sys_mut());
402394
result

godot-core/src/builtin/string.rs

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -37,43 +37,18 @@ impl GodotString {
3737
}
3838

3939
impl GodotFfi for GodotString {
40-
ffi_methods! {
41-
type sys::GDExtensionTypePtr = *mut Opaque;
42-
fn from_sys;
43-
fn sys;
44-
fn write_sys;
45-
}
46-
47-
unsafe fn from_sys_init(init_fn: impl FnOnce(sys::GDExtensionTypePtr)) -> Self {
48-
// Can't use uninitialized pointer -- String CoW implementation in C++ expects that on assignment,
49-
// the target CoW pointer is either initialized or nullptr
40+
ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque; .. }
5041

42+
unsafe fn from_sys_init_default(init_fn: impl FnOnce(sys::GDExtensionTypePtr)) -> Self {
5143
let mut result = Self::default();
5244
init_fn(result.sys_mut());
5345
result
5446
}
5547
}
5648

57-
impl Default for GodotString {
58-
fn default() -> Self {
59-
// Note: can't use from_sys_init(), as that calls the default constructor
60-
// (because most assignments expect initialized target type)
61-
62-
let mut uninit = std::mem::MaybeUninit::<GodotString>::uninit();
63-
64-
unsafe {
65-
let self_ptr = (*uninit.as_mut_ptr()).sys_mut();
66-
sys::builtin_call! {
67-
string_construct_default(self_ptr, std::ptr::null_mut())
68-
};
69-
70-
uninit.assume_init()
71-
}
72-
}
73-
}
74-
7549
impl_builtin_traits! {
7650
for GodotString {
51+
Default => string_construct_default;
7752
Clone => string_construct_copy;
7853
Drop => string_destroy;
7954
Eq => string_operator_equal;

godot-core/src/builtin/string_name.rs

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,9 @@ impl StringName {
3333
}
3434

3535
impl GodotFfi for StringName {
36-
ffi_methods! {
37-
type sys::GDExtensionTypePtr = *mut Opaque;
38-
fn from_sys;
39-
fn sys;
40-
fn write_sys;
41-
}
42-
43-
unsafe fn from_sys_init(init_fn: impl FnOnce(sys::GDExtensionTypePtr)) -> Self {
44-
// Can't use uninitialized pointer -- StringName implementation in C++ expects that on assignment,
45-
// the target type is a valid string (possibly empty)
36+
ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque; .. }
4637

38+
unsafe fn from_sys_init_default(init_fn: impl FnOnce(sys::GDExtensionTypePtr)) -> Self {
4739
let mut result = Self::default();
4840
init_fn(result.sys_mut());
4941
result
@@ -106,7 +98,7 @@ impl Hash for StringName {
10698
impl From<&GodotString> for StringName {
10799
fn from(s: &GodotString) -> Self {
108100
unsafe {
109-
Self::from_sys_init(|self_ptr| {
101+
Self::from_sys_init_default(|self_ptr| {
110102
let ctor = sys::builtin_fn!(string_name_from_string);
111103
let args = [s.sys_const()];
112104
ctor(self_ptr, args.as_ptr());
@@ -128,7 +120,7 @@ where
128120
impl From<&StringName> for GodotString {
129121
fn from(s: &StringName) -> Self {
130122
unsafe {
131-
Self::from_sys_init(|self_ptr| {
123+
Self::from_sys_init_default(|self_ptr| {
132124
let ctor = sys::builtin_fn!(string_from_string_name);
133125
let args = [s.sys_const()];
134126
ctor(self_ptr, args.as_ptr());

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

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,19 +55,21 @@ macro_rules! impl_variant_traits {
5555

5656
impl FromVariant for $T {
5757
fn try_from_variant(variant: &Variant) -> Result<Self, VariantConversionError> {
58+
// Type check -- at the moment, a strict match is required.
59+
if variant.get_type() != Self::variant_type() {
60+
return Err(VariantConversionError)
61+
}
62+
5863
// In contrast to T -> Variant, the conversion Variant -> T assumes
5964
// that the destination is initialized (at least for some T). For example:
6065
// void String::operator=(const String &p_str) { _cowdata._ref(p_str._cowdata); }
6166
// does a copy-on-write and explodes if this->_cowdata is not initialized.
6267
// We can thus NOT use Self::from_sys_init().
63-
if variant.get_type() != Self::variant_type() {
64-
return Err(VariantConversionError)
65-
}
66-
let mut value = <$T>::default();
6768
let result = unsafe {
68-
let converter = sys::builtin_fn!($to_fn);
69-
converter(value.sys_mut(), variant.var_sys());
70-
value
69+
Self::from_sys_init_default(|self_ptr| {
70+
let converter = sys::builtin_fn!($to_fn);
71+
converter(self_ptr, variant.var_sys());
72+
})
7173
};
7274

7375
Ok(result)

0 commit comments

Comments
 (0)