Skip to content

Commit

Permalink
Fix return virtual method type and add another virtual method return …
Browse files Browse the repository at this point in the history
…test

Make test that causes unrelated memory leak `#[itest(skip)]`
  • Loading branch information
lilizoey committed Apr 11, 2023
1 parent ae108f4 commit 931a28a
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 21 deletions.
4 changes: 4 additions & 0 deletions godot-codegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ const SELECTED_CLASSES: &[&str] = &[
"AudioStreamPlayer",
"BaseButton",
"Button",
"BoxMesh",
"Camera2D",
"Camera3D",
"CanvasItem",
Expand All @@ -276,6 +277,7 @@ const SELECTED_CLASSES: &[&str] = &[
"Label",
"MainLoop",
"Marker2D",
"Mesh",
"Node",
"Node2D",
"Node3D",
Expand All @@ -285,9 +287,11 @@ const SELECTED_CLASSES: &[&str] = &[
"PackedScene",
"PathFollow2D",
"PhysicsBody2D",
"PrimitiveMesh",
"RefCounted",
"RenderingServer",
"Resource",
"ResourceFormatLoader",
"ResourceLoader",
"RigidBody2D",
"SceneTree",
Expand Down
2 changes: 2 additions & 0 deletions godot-codegen/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ pub fn make_enum_definition(enum_: &Enum) -> TokenStream {
self.ord
}
}
// SAFETY:
// The enums are transparently represented as an `i32`, so `*mut Self` is sound.
unsafe impl sys::GodotFfi for #enum_name {
sys::ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
}
Expand Down
2 changes: 1 addition & 1 deletion godot-core/src/builtin/dictionary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ unsafe impl GodotFfi for Dictionary {
}

// SAFETY:
// Dictionaries are properly initialized through a `from_sys` call, but the ref-count should be
// Dictionaries are properly initialized through a `from_sys` call, but the ref-count should be
// incremented as that is the callee's responsibility.
//
// Using `std::mem::forget(dictionary.share())` increments the ref count.
Expand Down
2 changes: 1 addition & 1 deletion godot-ffi/src/godot_ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ macro_rules! ffi_methods_rest {
///
/// ## Using `Opaque`
///
/// Turning pointer call arguments into a value is simply calling `from_opaue` on the argument pointer.
/// Turning pointer call arguments into a value is simply calling `from_opaque` on the argument pointer.
/// Returning a value from a pointer call is simply calling [`std::ptr::swap`] on the return pointer
/// and the `opaque` field transmuted into a pointer.
///
Expand Down
145 changes: 126 additions & 19 deletions itest/rust/src/virtual_methods_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,19 @@ use crate::TestContext;
use godot::bind::{godot_api, GodotClass};
use godot::builtin::GodotString;
use godot::engine::node::InternalMode;
use godot::engine::resource_loader::CacheMode;
use godot::engine::{
InputEvent, InputEventAction, Node, Node2D, Node2DVirtual, NodeVirtual, RefCounted,
RefCountedVirtual,
BoxMesh, InputEvent, InputEventAction, Node, Node2D, Node2DVirtual, PrimitiveMesh,
PrimitiveMeshVirtual, RefCounted, RefCountedVirtual, ResourceFormatLoader,
ResourceFormatLoaderVirtual, ResourceLoader,
};
use godot::obj::{Base, Gd, Share};
use godot::prelude::PackedStringArray;
use godot::prelude::{
is_equal_approx, varray, Color, PackedByteArray, PackedColorArray, PackedFloat32Array,
PackedInt32Array, PackedStringArray, PackedVector2Array, PackedVector3Array, ToVariant,
Variant, VariantArray, Vector2, Vector3,
};
use godot::private::class_macros::assert_eq_approx;
use godot::test::itest;

/// Simple class, that deliberately has no constructor accessible from GDScript
Expand Down Expand Up @@ -96,22 +103,30 @@ impl Node2DVirtual for TreeVirtualTest {
}

#[derive(GodotClass, Debug)]
#[class(base=Node)]
#[class(init, base=PrimitiveMesh)]
struct ReturnVirtualTest {
#[base]
base: Base<Node>,
base: Base<PrimitiveMesh>,
}

#[godot_api]
impl NodeVirtual for ReturnVirtualTest {
fn init(base: Base<Node>) -> Self {
ReturnVirtualTest { base }
}

fn get_configuration_warnings(&self) -> PackedStringArray {
let mut output = PackedStringArray::new();
output.push("Hello".into());
output
impl PrimitiveMeshVirtual for ReturnVirtualTest {
fn create_mesh_array(&self) -> VariantArray {
varray![
PackedVector3Array::from_iter([Vector3::LEFT].into_iter()),
PackedVector3Array::from_iter([Vector3::LEFT].into_iter()),
PackedFloat32Array::from_iter([0.0, 0.0, 0.0, 1.0].into_iter()),
PackedColorArray::from_iter([Color::from_rgb(1.0, 1.0, 1.0)]),
PackedVector2Array::from_iter([Vector2::LEFT]),
PackedVector2Array::from_iter([Vector2::LEFT]),
PackedByteArray::from_iter([0, 1, 2, 3].into_iter()),
PackedByteArray::from_iter([0, 1, 2, 3].into_iter()),
PackedByteArray::from_iter([0, 1, 2, 3].into_iter()),
PackedByteArray::from_iter([0, 1, 2, 3].into_iter()),
PackedInt32Array::from_iter([0, 1, 2, 3].into_iter()),
PackedFloat32Array::from_iter([0.0, 1.0, 2.0, 3.0].into_iter()),
PackedInt32Array::from_iter([0].into_iter()),
]
}
}

Expand All @@ -130,11 +145,52 @@ impl Node2DVirtual for InputVirtualTest {
}

fn input(&mut self, event: Gd<InputEvent>) {
println!("nya");
self.event = Some(event);
}
}

#[derive(GodotClass, Debug)]
#[class(init, base=ResourceFormatLoader)]
struct FormatLoaderTest {
#[base]
base: Base<ResourceFormatLoader>,
}

impl FormatLoaderTest {
fn resource_type() -> GodotString {
GodotString::from("foo")
}
}

#[godot_api]
impl ResourceFormatLoaderVirtual for FormatLoaderTest {
fn get_recognized_extensions(&self) -> PackedStringArray {
[GodotString::from("extension")].into_iter().collect()
}

fn handles_type(&self, type_: godot::prelude::StringName) -> bool {
type_.to_string() == Self::resource_type().to_string()
}

fn get_resource_type(&self, _path: GodotString) -> GodotString {
Self::resource_type()
}

fn exists(&self, _path: GodotString) -> bool {
true
}

fn load(
&self,
_path: GodotString,
_original_path: GodotString,
_use_sub_threads: bool,
_cache_mode: i64,
) -> Variant {
BoxMesh::new().to_variant()
}
}

// ----------------------------------------------------------------------------------------------------------------------------------------------

#[itest]
Expand Down Expand Up @@ -263,10 +319,61 @@ fn test_tree_enters_exits(test_context: &TestContext) {
#[itest]
fn test_virtual_method_with_return(_test_context: &TestContext) {
let obj = Gd::<ReturnVirtualTest>::new_default();
let output = obj.bind().get_configuration_warnings();
assert!(output.contains("Hello".into()));
assert_eq!(output.len(), 1);
obj.free();
let arr = obj.share().upcast::<PrimitiveMesh>().get_mesh_arrays();
let arr_rust = obj.bind().create_mesh_array();
assert_eq!(arr.len(), arr_rust.len());
// can't just assert_eq because the values of some floats change slightly
assert_eq_approx!(
arr.get(0).to::<PackedVector3Array>().get(0),
arr_rust.get(0).to::<PackedVector3Array>().get(0),
Vector3::is_equal_approx
);
assert_eq_approx!(
arr.get(2).to::<PackedFloat32Array>().get(3),
arr_rust.get(2).to::<PackedFloat32Array>().get(3),
is_equal_approx
);
assert_eq_approx!(
arr.get(3).to::<PackedColorArray>().get(0),
arr_rust.get(3).to::<PackedColorArray>().get(0),
Color::is_equal_approx
);
assert_eq_approx!(
arr.get(4).to::<PackedVector2Array>().get(0),
arr_rust.get(4).to::<PackedVector2Array>().get(0),
Vector2::is_equal_approx
);
assert_eq!(
arr.get(6).to::<PackedByteArray>(),
arr_rust.get(6).to::<PackedByteArray>(),
);
assert_eq!(
arr.get(10).to::<PackedInt32Array>(),
arr_rust.get(10).to::<PackedInt32Array>()
);
}

// TODO: Fix memory leak in this test.
#[itest(skip)]
fn test_format_loader(_test_context: &TestContext) {
let format_loader = Gd::<FormatLoaderTest>::new_default();
let mut loader = ResourceLoader::singleton();
loader.add_resource_format_loader(format_loader.share().upcast(), true);

let extensions = loader.get_recognized_extensions_for_type(FormatLoaderTest::resource_type());
let mut extensions_rust = format_loader.bind().get_recognized_extensions();
extensions_rust.push("tres".into());
assert_eq!(extensions, extensions_rust);
let resource = loader
.load(
"path.extension".into(),
"".into(),
CacheMode::CACHE_MODE_IGNORE,
)
.unwrap();
assert!(resource.try_cast::<BoxMesh>().is_some());

loader.remove_resource_format_loader(format_loader.upcast());
}

fn test_input_event(test_context: &TestContext) {
Expand Down

0 comments on commit 931a28a

Please sign in to comment.