Skip to content

Commit b3086b5

Browse files
authored
Merge pull request #948 from godot-rust/qol/meta-args-module
Cleanup around `godot::meta` argument conversions
2 parents de0841f + 3c43cf2 commit b3086b5

File tree

18 files changed

+111
-60
lines changed

18 files changed

+111
-60
lines changed

godot-codegen/src/util.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,10 @@ pub fn make_imports() -> TokenStream {
2525
quote! {
2626
use godot_ffi as sys;
2727
use crate::builtin::*;
28-
use crate::meta::{AsArg, ClassName, CowArg, PtrcallSignatureTuple, RefArg, VarcallSignatureTuple};
28+
use crate::meta::{AsArg, AsObjectArg, ClassName, CowArg, ObjectArg, ObjectCow, PtrcallSignatureTuple, RefArg, VarcallSignatureTuple};
2929
use crate::classes::native::*;
3030
use crate::classes::Object;
31-
use crate::obj::{Gd, AsObjectArg};
32-
use crate::obj::object_arg::{ObjectArg, ObjectCow};
31+
use crate::obj::Gd;
3332
use crate::sys::GodotFfi as _;
3433
}
3534
}

godot-core/src/builtin/callable.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,15 @@ impl Callable {
4646
pub fn from_object_method<T, S>(object: &Gd<T>, method_name: S) -> Self
4747
where
4848
T: GodotClass, // + Inherits<Object>,
49-
S: Into<StringName>,
49+
S: meta::AsArg<StringName>,
5050
{
51-
// upcast not needed
52-
let method = method_name.into();
51+
meta::arg_into_ref!(method_name);
52+
5353
unsafe {
5454
Self::new_with_uninit(|self_ptr| {
5555
let ctor = sys::builtin_fn!(callable_from_object_method);
5656
let raw = object.to_ffi();
57-
let args = [raw.as_arg_ptr(), method.sys()];
57+
let args = [raw.as_arg_ptr(), method_name.sys()];
5858
ctor(self_ptr, args.as_ptr());
5959
})
6060
}
@@ -340,6 +340,7 @@ impl fmt::Display for Callable {
340340
#[cfg(since_api = "4.2")]
341341
use custom_callable::*;
342342

343+
use crate::meta;
343344
#[cfg(since_api = "4.2")]
344345
pub use custom_callable::RustCallable;
345346

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ use crate::builtin::*;
1212
use crate::meta;
1313
use crate::meta::error::{ConvertError, FromGodotError, FromVariantError};
1414
use crate::meta::{
15-
ApiParam, ArrayElement, ArrayTypeInfo, AsArg, CowArg, FromGodot, GodotConvert, GodotFfiVariant,
16-
GodotType, PropertyHintInfo, RefArg, ToGodot,
15+
ArrayElement, ArrayTypeInfo, AsArg, CowArg, FromGodot, GodotConvert, GodotFfiVariant,
16+
GodotType, ParamType, PropertyHintInfo, RefArg, ToGodot,
1717
};
1818
use crate::registry::property::{Export, Var};
1919
use godot_ffi as sys;
@@ -944,7 +944,7 @@ impl<'r, T: ArrayElement> AsArg<Array<T>> for &'r Array<T> {
944944
}
945945
}
946946

947-
impl<T: ArrayElement> ApiParam for Array<T> {
947+
impl<T: ArrayElement> ParamType for Array<T> {
948948
type Arg<'v> = CowArg<'v, Self>;
949949

950950
fn owned_to_arg<'v>(self) -> Self::Arg<'v> {
@@ -1221,7 +1221,7 @@ impl<T: ArrayElement + ToGodot> Extend<T> for Array<T> {
12211221
// A faster implementation using `resize()` and direct pointer writes might still be possible.
12221222
// Note that this could technically also use iter(), since no moves need to happen (however Extend requires IntoIterator).
12231223
for item in iter.into_iter() {
1224-
self.push(ApiParam::owned_to_arg(item));
1224+
self.push(ParamType::owned_to_arg(item));
12251225
}
12261226
}
12271227
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ macro_rules! impl_packed_array {
491491
// A faster implementation using `resize()` and direct pointer writes might still be
492492
// possible.
493493
for item in iter.into_iter() {
494-
self.push(meta::ApiParam::owned_to_arg(item));
494+
self.push(meta::ParamType::owned_to_arg(item));
495495
}
496496
}
497497
}

godot-core/src/builtin/signal.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use godot_ffi as sys;
1313
use crate::builtin::{inner, Array, Callable, Dictionary, StringName, Variant};
1414
use crate::classes::Object;
1515
use crate::global::Error;
16+
use crate::meta;
1617
use crate::meta::{FromGodot, GodotType, ToGodot};
1718
use crate::obj::bounds::DynMemory;
1819
use crate::obj::{Bounds, Gd, GodotClass, InstanceId};
@@ -40,9 +41,10 @@ impl Signal {
4041
pub fn from_object_signal<T, S>(object: &Gd<T>, signal_name: S) -> Self
4142
where
4243
T: GodotClass,
43-
S: Into<StringName>,
44+
S: meta::AsArg<StringName>,
4445
{
45-
let signal_name = signal_name.into();
46+
meta::arg_into_ref!(signal_name);
47+
4648
unsafe {
4749
Self::new_with_uninit(|self_ptr| {
4850
let ctor = sys::builtin_fn!(signal_from_object_signal);

godot-core/src/meta/as_arg.rs renamed to godot-core/src/meta/args/as_arg.rs

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,14 @@ use std::ffi::CStr;
1919
/// - `&T` for by-ref builtins: `GString`, `Array`, `Dictionary`, `Packed*Array`, `Variant`...
2020
/// - `&str`, `&String` additionally for string types `GString`, `StringName`, `NodePath`.
2121
///
22+
/// See also the [`AsObjectArg`][crate::meta::AsObjectArg] trait which is specialized for object arguments. It may be merged with `AsArg`
23+
/// in the future.
24+
///
2225
/// # Pass by value
2326
/// Implicitly converting from `T` for by-ref builtins is explicitly not supported. This emphasizes that there is no need to consume the object,
2427
/// thus discourages unnecessary cloning.
2528
///
26-
/// If you need to pass owned values in generic code, you can use [`ApiParam::owned_to_arg()`].
29+
/// If you need to pass owned values in generic code, you can use [`ParamType::owned_to_arg()`].
2730
///
2831
/// # Performance for strings
2932
/// Godot has three string types: [`GString`], [`StringName`] and [`NodePath`]. Conversions between those three, as well as between `String` and
@@ -43,19 +46,19 @@ use std::ffi::CStr;
4346
/// you can only forward it as-is to a Godot API -- there are no stable APIs to access the inner object yet.
4447
///
4548
/// Furthermore, there is currently no benefit in implementing `AsArg` for your own types, as it's only used by Godot APIs which don't accept
46-
/// custom types. Classes are already supported through upcasting and [`AsObjectArg`][crate::obj::AsObjectArg].
49+
/// custom types. Classes are already supported through upcasting and [`AsObjectArg`][crate::meta::AsObjectArg].
4750
#[diagnostic::on_unimplemented(
4851
message = "Argument of type `{Self}` cannot be passed to an `impl AsArg<{T}>` parameter",
4952
note = "If you pass by value, consider borrowing instead.",
5053
note = "GString/StringName/NodePath aren't implicitly convertible for performance reasons; use their `arg()` method.",
5154
note = "See also `AsArg` docs: https://godot-rust.github.io/docs/gdext/master/godot/meta/trait.AsArg.html"
5255
)]
53-
pub trait AsArg<T: ApiParam>
56+
pub trait AsArg<T: ParamType>
5457
where
5558
Self: Sized,
5659
{
5760
#[doc(hidden)]
58-
fn into_arg<'r>(self) -> <T as ApiParam>::Arg<'r>
61+
fn into_arg<'r>(self) -> <T as ParamType>::Arg<'r>
5962
where
6063
Self: 'r;
6164
}
@@ -77,7 +80,7 @@ macro_rules! arg_into_ref {
7780
};
7881
($arg_variable:ident: $T:ty) => {
7982
let $arg_variable = $arg_variable.into_arg();
80-
let $arg_variable: &$T = $crate::meta::ApiParam::arg_to_ref(&$arg_variable);
83+
let $arg_variable: &$T = $crate::meta::ParamType::arg_to_ref(&$arg_variable);
8184
};
8285
}
8386

@@ -89,21 +92,21 @@ macro_rules! arg_into_owned {
8992
($arg_variable:ident) => {
9093
let $arg_variable = $arg_variable.into_arg();
9194
let $arg_variable = $arg_variable.cow_into_owned();
92-
// cow_into_owned() is not yet used generically; could be abstracted in ApiParam::arg_to_owned() as well.
95+
// cow_into_owned() is not yet used generically; could be abstracted in ParamType::arg_to_owned() as well.
9396
};
9497
}
9598

9699
#[macro_export]
97100
macro_rules! impl_asarg_by_value {
98101
($T:ty) => {
99102
impl $crate::meta::AsArg<$T> for $T {
100-
fn into_arg<'r>(self) -> <$T as $crate::meta::ApiParam>::Arg<'r> {
103+
fn into_arg<'r>(self) -> <$T as $crate::meta::ParamType>::Arg<'r> {
101104
// Moves value (but typically a Copy type).
102105
self
103106
}
104107
}
105108

106-
impl $crate::meta::ApiParam for $T {
109+
impl $crate::meta::ParamType for $T {
107110
type Arg<'v> = $T;
108111

109112
fn owned_to_arg<'v>(self) -> Self::Arg<'v> {
@@ -128,15 +131,15 @@ macro_rules! impl_asarg_by_ref {
128131
// Thus, keep `where` on same line.
129132
// type ArgType<'v> = &'v $T where Self: 'v;
130133

131-
fn into_arg<'cow>(self) -> <$T as $crate::meta::ApiParam>::Arg<'cow>
134+
fn into_arg<'cow>(self) -> <$T as $crate::meta::ParamType>::Arg<'cow>
132135
where
133136
'r: 'cow, // Original reference must be valid for at least as long as the returned cow.
134137
{
135138
$crate::meta::CowArg::Borrowed(self)
136139
}
137140
}
138141

139-
impl $crate::meta::ApiParam for $T {
142+
impl $crate::meta::ParamType for $T {
140143
type Arg<'v> = $crate::meta::CowArg<'v, $T>;
141144

142145
fn owned_to_arg<'v>(self) -> Self::Arg<'v> {
@@ -157,11 +160,11 @@ macro_rules! declare_arg_method {
157160
///
158161
/// # Generic bounds
159162
/// The bounds are implementation-defined and may change at any time. Do not use this function in a generic context requiring `T`
160-
/// -- use the `From` trait or [`ApiParam`][crate::meta::ApiParam] in that case.
163+
/// -- use the `From` trait or [`ParamType`][crate::meta::ParamType] in that case.
161164
pub fn arg<T>(&self) -> impl $crate::meta::AsArg<T>
162165
where
163166
for<'a> T: From<&'a Self>
164-
+ $crate::meta::ApiParam<Arg<'a> = $crate::meta::CowArg<'a, T>>
167+
+ $crate::meta::ParamType<Arg<'a> = $crate::meta::CowArg<'a, T>>
165168
+ 'a,
166169
{
167170
$crate::meta::CowArg::Owned(T::from(self))
@@ -178,7 +181,7 @@ macro_rules! declare_arg_method {
178181
/// This is necessary for packed array dispatching to different "inner" backend signatures.
179182
impl<'a, T> AsArg<T> for CowArg<'a, T>
180183
where
181-
for<'r> T: ApiParam<Arg<'r> = CowArg<'r, T>> + 'r,
184+
for<'r> T: ParamType<Arg<'r> = CowArg<'r, T>> + 'r,
182185
{
183186
fn into_arg<'r>(self) -> CowArg<'r, T>
184187
where
@@ -188,7 +191,7 @@ where
188191
}
189192
}
190193

191-
// impl<'a, T> ApiParam for CowArg<'a, T> {
194+
// impl<'a, T> ParamType for CowArg<'a, T> {
192195
// type Type<'v> = CowArg<'v, T>
193196
// where Self: 'v;
194197
// }
@@ -250,7 +253,7 @@ impl AsArg<NodePath> for &String {
250253
// ----------------------------------------------------------------------------------------------------------------------------------------------
251254

252255
/// Implemented for all parameter types `T` that are allowed to receive [impl `AsArg<T>`][AsArg].
253-
pub trait ApiParam: GodotType
256+
pub trait ParamType: GodotType
254257
// GodotType bound not required right now, but conceptually should always be the case.
255258
{
256259
/// Canonical argument passing type, either `T` or an internally-used CoW type.

godot-core/src/meta/cow_arg.rs renamed to godot-core/src/meta/args/cow_arg.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ impl<'r, T> CowArg<'r, T> {
4747
}
4848
}
4949

50-
/// Exists for polymorphism in [`crate::meta::ApiParam`].
50+
/// Exists for polymorphism in [`crate::meta::ParamType`].
5151
///
5252
/// Necessary for generics in e.g. `Array<T>`, when accepting `impl AsArg<T>` parameters.
5353
///

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright (c) godot-rust; Bromeon and contributors.
3+
* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
6+
*/
7+
8+
mod as_arg;
9+
mod cow_arg;
10+
mod object_arg;
11+
mod ref_arg;
12+
13+
// ----------------------------------------------------------------------------------------------------------------------------------------------
14+
// Public APIs
15+
16+
pub use as_arg::{AsArg, ParamType};
17+
pub use object_arg::AsObjectArg;
18+
pub use ref_arg::RefArg;
19+
20+
// ----------------------------------------------------------------------------------------------------------------------------------------------
21+
// Internal APIs
22+
23+
// Solely public for itest/convert_test.rs.
24+
#[cfg(feature = "trace")]
25+
#[doc(hidden)]
26+
pub use cow_arg::CowArg;
27+
#[cfg(not(feature = "trace"))]
28+
pub(crate) use cow_arg::CowArg;
29+
30+
#[allow(unused_imports)] // ObjectCow is used in generated code.
31+
pub(crate) use object_arg::{ObjectArg, ObjectCow, ObjectNullArg};
32+
33+
// #[doc(hidden)]
34+
// pub use cow_arg::*;
35+
//
36+
// #[doc(hidden)]
37+
// pub use ref_arg::*;

godot-core/src/obj/object_arg.rs renamed to godot-core/src/meta/args/object_arg.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
use crate::builtin::Variant;
99
use crate::meta::error::ConvertError;
1010
use crate::meta::{ClassName, FromGodot, GodotConvert, GodotFfiVariant, GodotType, ToGodot};
11-
use crate::obj::{bounds, raw_gd, Bounds, Gd, GodotClass, Inherits, RawGd};
12-
use crate::sys;
11+
use crate::obj::{bounds, Bounds, Gd, GodotClass, Inherits, RawGd};
12+
use crate::{obj, sys};
1313
use godot_ffi::{GodotFfi, GodotNullableFfi, PtrcallType};
1414
use std::ptr;
1515

@@ -20,6 +20,8 @@ use std::ptr;
2020
/// - [`Option<&Gd<T>>`][Option], to pass optional objects. `None` is mapped to a null argument.
2121
/// - [`Gd::null_arg()`], to pass `null` arguments without using `Option`.
2222
///
23+
/// Note that [`AsObjectArg`] is very similar to the more general [`AsArg`][crate::meta::AsArg] trait. The two may be merged in the future.
24+
///
2325
/// # Nullability
2426
/// <div class="warning">
2527
/// The GDExtension API does not inform about nullability of its function parameters. It is up to you to verify that the arguments you pass
@@ -281,7 +283,7 @@ where
281283
// https://github.com/godotengine/godot-cpp/issues/954
282284

283285
fn as_arg_ptr(&self) -> sys::GDExtensionConstTypePtr {
284-
raw_gd::object_as_arg_ptr(&self.object_ptr)
286+
obj::object_as_arg_ptr(&self.object_ptr)
285287
}
286288

287289
unsafe fn from_arg_ptr(_ptr: sys::GDExtensionTypePtr, _call_type: PtrcallType) -> Self {
@@ -341,7 +343,7 @@ impl<T: GodotClass> GodotType for ObjectArg<T> {
341343
impl<T: GodotClass> GodotFfiVariant for ObjectArg<T> {
342344
fn ffi_to_variant(&self) -> Variant {
343345
// Note: currently likely not invoked since there are no known varcall APIs taking Object parameters; however this might change.
344-
raw_gd::object_ffi_to_variant(self)
346+
obj::object_ffi_to_variant(self)
345347
}
346348

347349
fn ffi_from_variant(_variant: &Variant) -> Result<Self, ConvertError> {
File renamed without changes.

godot-core/src/meta/mod.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
66
*/
77

8-
//! Meta-information about variant types, properties and class names.
8+
//! Meta-information about Godot types, their properties and conversions between them.
99
//!
1010
//! # Conversions between types
1111
//!
@@ -33,16 +33,23 @@
3333
//! Godot classes exist in a hierarchy. In OOP, it is usually possible to represent pointers to derived objects as pointer to their bases.
3434
//! For conversions between base and derived class objects, you can use `Gd` methods [`cast()`][crate::obj::Gd::cast],
3535
//! [`try_cast()`][crate::obj::Gd::try_cast] and [`upcast()`][crate::obj::Gd::upcast]. Upcasts are infallible.
36+
//!
37+
//! ## Argument conversions
38+
//!
39+
//! Rust does not support implicit conversions, however it has something very close: the `impl Into<T>` idiom, which can be used to convert
40+
//! "T-compatible" arguments into `T`. This library specializes this idea with two traits:
41+
//!
42+
//! - [`AsArg<T>`] allows argument conversions from arguments into `T`. This is most interesting in the context of strings (so you can pass
43+
//! `&str` to a function expecting `GString`), but is generic to support e.g. array insertion.
44+
//! - [`AsObjectArg<T>`] is a more specialized version of `AsArg` that is used for object arguments, i.e. `Gd<T>`.
3645
46+
mod args;
3747
mod array_type_info;
38-
mod as_arg;
3948
mod class_name;
4049
mod godot_convert;
4150
mod method_info;
4251
mod property_info;
43-
mod ref_arg;
4452
// RpcConfig uses MultiplayerPeer::TransferMode and MultiplayerApi::RpcMode, which are only enabled in `codegen-full` feature.
45-
mod cow_arg;
4653
#[cfg(feature = "codegen-full")]
4754
mod rpc_config;
4855
mod sealed;
@@ -51,7 +58,7 @@ mod traits;
5158

5259
pub mod error;
5360

54-
pub use as_arg::*;
61+
pub use args::*;
5562
pub use class_name::ClassName;
5663
pub use godot_convert::{FromGodot, GodotConvert, ToGodot};
5764
#[cfg(feature = "codegen-full")]
@@ -68,10 +75,6 @@ pub(crate) use crate::{
6875
impl_godot_as_self,
6976
};
7077

71-
#[doc(hidden)]
72-
pub use cow_arg::*;
73-
#[doc(hidden)]
74-
pub use ref_arg::*;
7578
#[doc(hidden)]
7679
pub use signature::*;
7780

godot-core/src/meta/sealed.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
1010
// To ensure the user does not implement `GodotType` for their own types.
1111
use crate::builtin::*;
12+
use crate::meta;
1213
use crate::meta::traits::{ArrayElement, GodotNullableFfi, GodotType};
13-
use crate::obj::*;
14+
use crate::obj::{Gd, GodotClass, RawGd};
1415

1516
pub trait Sealed {}
1617
impl Sealed for Aabb {}
@@ -63,7 +64,7 @@ impl Sealed for Variant {}
6364
impl<T: ArrayElement> Sealed for Array<T> {}
6465
impl<T: GodotClass> Sealed for Gd<T> {}
6566
impl<T: GodotClass> Sealed for RawGd<T> {}
66-
impl<T: GodotClass> Sealed for object_arg::ObjectArg<T> {}
67+
impl<T: GodotClass> Sealed for meta::ObjectArg<T> {}
6768
impl<T> Sealed for Option<T>
6869
where
6970
T: GodotType,

0 commit comments

Comments
 (0)