Skip to content

Commit

Permalink
Fix return virtual method type
Browse files Browse the repository at this point in the history
Add another virtual method return test
Make test that causes memory leak use `#[itest(skip)]`
  • Loading branch information
lilizoey committed Apr 11, 2023
1 parent b5e74b3 commit c3273b6
Show file tree
Hide file tree
Showing 5 changed files with 136 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
147 changes: 128 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,25 +103,34 @@ 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()),
]
}
}

#[derive(GodotClass, Debug)]
#[class(base=Node2D)]
struct InputVirtualTest {
#[base]
Expand All @@ -129,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 @@ -262,12 +319,64 @@ 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());
}

#[itest]
fn test_input_event(test_context: &TestContext) {
let obj = Gd::<InputVirtualTest>::new_default();
assert_eq!(obj.bind().event, None);
Expand Down

0 comments on commit c3273b6

Please sign in to comment.