Skip to content

Commit afbd2cd

Browse files
bors[bot]BromeonthebigGlilizoey
authored
Merge #204
204: Fix various issues with pointer calls r=Bromeon a=sayaks Combines #165 and #200 with more complete fixes. # Overview Properly clones strings and shares arrays/dictionaries in pointer calls to ensure they're not prematurely freed. Frees the value currently in the `ret` pointer in pointer calls, to avoid memory leak. Moves `ret_val` into `ret`, to avoid premature destruction. Changes integer conversions in pointer calls to use `as`, since that seems like the right way of converting the values we get from godot. `try_from` lead to wrong conversions sometimes. Objects inheriting from `RefCounted` now use `ref_get_object` and `ref_set_object` in virtual method calls. # Details Add `from_arg_ptr` and `move_return_ptr` to `GodotFfi` that will be used when converting argument pointers in pointer calls, and moving things into a pointer. Add `CallType` so `from_arg_ptr` and `move_return_ptr` can have different behavior depending on whether it's a virtual method call or not. Remove `write_sys` in `GodotFfi`. Override `from_arg_ptr` in `GodotString`, `NodePath`, `StringName`, `Array`, `Dictionary`, `Gd`. Override `move_return_ptr` in `Gd`. Rename `try_write_sys` to `try_return`, and have it use `move_return_ptr` instead of `write_sys`. Rename `try_from_sys` to `try_from_arg`, and have it use `from_arg_ptr` instead of `from_sys`. Add `u8`, `u16`, `u32` to the ptrcall tests. Add a couple of test of virtual methods. Fix a test for virtual method with return values to actually call the virtual method as a virtual method. closes #195 closes #189 Co-authored-by: Jan Haller <[email protected]> Co-authored-by: thebigG <[email protected]> Co-authored-by: Lili Zoey <[email protected]>
2 parents 558a6d3 + 8206697 commit afbd2cd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1069
-328
lines changed

godot-codegen/src/central_generator.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,9 @@ fn make_sys_code(central_items: &CentralItems) -> String {
176176
}
177177
}
178178

179-
impl GodotFfi for VariantType {
179+
// SAFETY:
180+
// This type is represented as `Self` in Godot, so `*mut Self` is sound.
181+
unsafe impl GodotFfi for VariantType {
180182
ffi_methods! { type GDExtensionTypePtr = *mut Self; .. }
181183
}
182184

@@ -205,7 +207,9 @@ fn make_sys_code(central_items: &CentralItems) -> String {
205207
}
206208
}
207209

208-
impl GodotFfi for VariantOperator {
210+
// SAFETY:
211+
// This type is represented as `Self` in Godot, so `*mut Self` is sound.
212+
unsafe impl GodotFfi for VariantOperator {
209213
ffi_methods! { type GDExtensionTypePtr = *mut Self; .. }
210214
}
211215
};

godot-codegen/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ const SELECTED_CLASSES: &[&str] = &[
258258
"AudioStreamPlayer",
259259
"BaseButton",
260260
"Button",
261+
"BoxMesh",
261262
"Camera2D",
262263
"Camera3D",
263264
"CanvasItem",
@@ -271,9 +272,12 @@ const SELECTED_CLASSES: &[&str] = &[
271272
"Image",
272273
"ImageTextureLayered",
273274
"Input",
275+
"InputEvent",
276+
"InputEventAction",
274277
"Label",
275278
"MainLoop",
276279
"Marker2D",
280+
"Mesh",
277281
"Node",
278282
"Node2D",
279283
"Node3D",
@@ -283,9 +287,11 @@ const SELECTED_CLASSES: &[&str] = &[
283287
"PackedScene",
284288
"PathFollow2D",
285289
"PhysicsBody2D",
290+
"PrimitiveMesh",
286291
"RefCounted",
287292
"RenderingServer",
288293
"Resource",
294+
"ResourceFormatLoader",
289295
"ResourceLoader",
290296
"RigidBody2D",
291297
"SceneTree",
@@ -296,4 +302,6 @@ const SELECTED_CLASSES: &[&str] = &[
296302
"TextureLayered",
297303
"Time",
298304
"Timer",
305+
"Window",
306+
"Viewport",
299307
];

godot-codegen/src/util.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,9 @@ pub fn make_enum_definition(enum_: &Enum) -> TokenStream {
9999
self.ord
100100
}
101101
}
102-
impl sys::GodotFfi for #enum_name {
102+
// SAFETY:
103+
// The enums are transparently represented as an `i32`, so `*mut Self` is sound.
104+
unsafe impl sys::GodotFfi for #enum_name {
103105
sys::ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
104106
}
105107
#bitfield_ops

godot-core/src/builtin/aabb.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ impl Aabb {
8282
*/
8383
}
8484

85-
impl GodotFfi for Aabb {
85+
// SAFETY:
86+
// This type is represented as `Self` in Godot, so `*mut Self` is sound.
87+
unsafe impl GodotFfi for Aabb {
8688
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
8789
}

godot-core/src/builtin/array.rs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -566,8 +566,27 @@ impl<T: VariantMetadata + ToVariant> Array<T> {
566566
// ...
567567
// }
568568

569-
impl<T: VariantMetadata> GodotFfi for Array<T> {
570-
ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque; .. }
569+
// SAFETY:
570+
// - `move_return_ptr`
571+
// Nothing special needs to be done beyond a `std::mem::swap` when returning an Array.
572+
// So we can just use `ffi_methods`.
573+
//
574+
// - `from_arg_ptr`
575+
// Arrays are properly initialized through a `from_sys` call, but the ref-count should be incremented
576+
// as that is the callee's responsibility. Which we do by calling `std::mem::forget(array.share())`.
577+
unsafe impl<T: VariantMetadata> GodotFfi for Array<T> {
578+
ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque;
579+
fn from_sys;
580+
fn sys;
581+
fn from_sys_init;
582+
fn move_return_ptr;
583+
}
584+
585+
unsafe fn from_arg_ptr(ptr: sys::GDExtensionTypePtr, _call_type: sys::PtrcallType) -> Self {
586+
let array = Self::from_sys(ptr);
587+
std::mem::forget(array.share());
588+
array
589+
}
571590

572591
unsafe fn from_sys_init_default(init_fn: impl FnOnce(sys::GDExtensionTypePtr)) -> Self {
573592
let mut result = Self::default();
@@ -855,7 +874,7 @@ macro_rules! varray {
855874
/// [`set_typed`](https://docs.godotengine.org/en/latest/classes/class_array.html#class-array-method-set-typed).
856875
///
857876
/// We ignore the `script` parameter because it has no impact on typing in Godot.
858-
#[derive(Debug, PartialEq, Eq)]
877+
#[derive(PartialEq, Eq)]
859878
struct TypeInfo {
860879
variant_type: VariantType,
861880
class_name: StringName,
@@ -880,3 +899,16 @@ impl TypeInfo {
880899
self.variant_type != VariantType::Nil
881900
}
882901
}
902+
903+
impl fmt::Debug for TypeInfo {
904+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
905+
let class = self.class_name.to_string();
906+
let class_str = if class.is_empty() {
907+
String::new()
908+
} else {
909+
format!(" (class={class})")
910+
};
911+
912+
write!(f, "{:?}{}", self.variant_type, class_str)
913+
}
914+
}

godot-core/src/builtin/basis.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,9 @@ impl Mul<Vector3> for Basis {
570570
}
571571
}
572572

573-
impl GodotFfi for Basis {
573+
// SAFETY:
574+
// This type is represented as `Self` in Godot, so `*mut Self` is sound.
575+
unsafe impl GodotFfi for Basis {
574576
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
575577
}
576578

godot-core/src/builtin/color.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,9 @@ impl Color {
311311
}
312312
}
313313

314-
impl GodotFfi for Color {
314+
// SAFETY:
315+
// This type is represented as `Self` in Godot, so `*mut Self` is sound.
316+
unsafe impl GodotFfi for Color {
315317
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
316318
}
317319

godot-core/src/builtin/dictionary.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,28 @@ impl Dictionary {
239239
// ----------------------------------------------------------------------------------------------------------------------------------------------
240240
// Traits
241241

242-
impl GodotFfi for Dictionary {
243-
ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque; .. }
242+
// SAFETY:
243+
// - `move_return_ptr`
244+
// Nothing special needs to be done beyond a `std::mem::swap` when returning an Dictionary.
245+
// So we can just use `ffi_methods`.
246+
//
247+
// - `from_arg_ptr`
248+
// Dictionaries are properly initialized through a `from_sys` call, but the ref-count should be
249+
// incremented as that is the callee's responsibility. Which we do by calling
250+
// `std::mem::forget(dictionary.share())`.
251+
unsafe impl GodotFfi for Dictionary {
252+
ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque;
253+
fn from_sys;
254+
fn from_sys_init;
255+
fn sys;
256+
fn move_return_ptr;
257+
}
258+
259+
unsafe fn from_arg_ptr(ptr: sys::GDExtensionTypePtr, _call_type: sys::PtrcallType) -> Self {
260+
let dictionary = Self::from_sys(ptr);
261+
std::mem::forget(dictionary.share());
262+
dictionary
263+
}
244264

245265
unsafe fn from_sys_init_default(init_fn: impl FnOnce(sys::GDExtensionTypePtr)) -> Self {
246266
let mut result = Self::default();

godot-core/src/builtin/macros.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,10 @@ macro_rules! impl_builtin_stub {
157157
}
158158
}
159159

160-
impl GodotFfi for $Class {
160+
// SAFETY:
161+
// This is simply a wrapper around an `Opaque` value representing a value of the type.
162+
// So this is safe.
163+
unsafe impl GodotFfi for $Class {
161164
ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque; .. }
162165
}
163166
};

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

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,14 @@ pub trait VariantMetadata {
2727
}
2828

2929
fn property_info(property_name: &str) -> PropertyInfo {
30-
PropertyInfo::new(
31-
Self::variant_type(),
32-
Self::class_name(),
33-
StringName::from(property_name),
34-
global::PropertyHint::PROPERTY_HINT_NONE,
35-
GodotString::new(),
36-
)
30+
PropertyInfo {
31+
variant_type: Self::variant_type(),
32+
class_name: Self::class_name(),
33+
property_name: StringName::from(property_name),
34+
hint: global::PropertyHint::PROPERTY_HINT_NONE,
35+
hint_string: GodotString::new(),
36+
usage: global::PropertyUsageFlags::PROPERTY_USAGE_DEFAULT,
37+
}
3738
}
3839

3940
fn param_metadata() -> sys::GDExtensionClassMethodArgumentMetadata {
@@ -52,33 +53,17 @@ impl<T: VariantMetadata> VariantMetadata for Option<T> {
5253
/// Rusty abstraction of sys::GDExtensionPropertyInfo
5354
/// Keeps the actual allocated values (the sys equivalent only keeps pointers, which fall out of scope)
5455
#[derive(Debug)]
56+
// Note: is not #[non_exhaustive], so adding fields is a breaking change. Mostly used internally at the moment though.
5557
pub struct PropertyInfo {
56-
variant_type: VariantType,
57-
class_name: ClassName,
58-
property_name: StringName,
59-
hint: global::PropertyHint,
60-
hint_string: GodotString,
61-
usage: global::PropertyUsageFlags,
58+
pub variant_type: VariantType,
59+
pub class_name: ClassName,
60+
pub property_name: StringName,
61+
pub hint: global::PropertyHint,
62+
pub hint_string: GodotString,
63+
pub usage: global::PropertyUsageFlags,
6264
}
6365

6466
impl PropertyInfo {
65-
pub fn new(
66-
variant_type: VariantType,
67-
class_name: ClassName,
68-
property_name: StringName,
69-
hint: global::PropertyHint,
70-
hint_string: GodotString,
71-
) -> Self {
72-
Self {
73-
variant_type,
74-
class_name,
75-
property_name,
76-
hint,
77-
hint_string,
78-
usage: global::PropertyUsageFlags::PROPERTY_USAGE_DEFAULT,
79-
}
80-
}
81-
8267
/// Converts to the FFI type. Keep this object allocated while using that!
8368
pub fn property_sys(&self) -> sys::GDExtensionPropertyInfo {
8469
use crate::obj::EngineEnum as _;

0 commit comments

Comments
 (0)