Skip to content

Commit e47c6b2

Browse files
committed
AsArg docs
1 parent a4c874e commit e47c6b2

File tree

4 files changed

+56
-46
lines changed

4 files changed

+56
-46
lines changed

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -945,13 +945,13 @@ impl<'r, T: ArrayElement> AsArg<Array<T>> for &'r Array<T> {
945945
}
946946

947947
impl<T: ArrayElement> ArgTarget for Array<T> {
948-
type Type<'v> = CowArg<'v, Self>;
948+
type Arg<'v> = CowArg<'v, Self>;
949949

950-
fn value_to_arg<'v>(self) -> Self::Type<'v> {
950+
fn value_to_arg<'v>(self) -> Self::Arg<'v> {
951951
CowArg::Owned(self)
952952
}
953953

954-
fn arg_to_ref<'r>(arg: &'r Self::Type<'_>) -> &'r Self {
954+
fn arg_to_ref<'r>(arg: &'r Self::Arg<'_>) -> &'r Self {
955955
arg.cow_as_ref()
956956
}
957957
}

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use godot_ffi as sys;
99

1010
use crate::builtin::*;
11-
use crate::meta::{Arg, AsArg, ToGodot};
11+
use crate::meta::{AsArg, ToGodot};
1212
use std::{fmt, ops, ptr};
1313
use sys::types::*;
1414
use sys::{ffi_methods, interface_fn, GodotFfi};
@@ -107,7 +107,7 @@ macro_rules! impl_packed_array {
107107
}
108108

109109
/// Returns the number of times a value is in the array.
110-
pub fn count(&self, value: Arg<$Element>) -> usize {
110+
pub fn count(&self, value: impl AsArg<$Element>) -> usize {
111111
to_usize(self.as_inner().count(value.into_arg().into_packed_arg()))
112112
}
113113

@@ -140,7 +140,7 @@ macro_rules! impl_packed_array {
140140
/// Note: On large arrays, this method is much slower than `push` as it will move all
141141
/// the array's elements after the inserted element. The larger the array, the slower
142142
/// `insert` will be.
143-
pub fn insert(&mut self, index: usize, value: Arg<$Element>) {
143+
pub fn insert(&mut self, index: usize, value: impl AsArg<$Element>) {
144144
// Intentional > and not >=.
145145
if index > self.len() {
146146
self.panic_out_of_bounds(index);
@@ -170,7 +170,7 @@ macro_rules! impl_packed_array {
170170

171171
/// Assigns the given value to all elements in the array. This can be used together
172172
/// with `resize` to create an array with a given size and initialized elements.
173-
pub fn fill(&mut self, value: Arg<$Element>) {
173+
pub fn fill(&mut self, value: impl AsArg<$Element>) {
174174
self.as_inner().fill(value.into_arg().into_packed_arg());
175175
}
176176

@@ -262,7 +262,7 @@ macro_rules! impl_packed_array {
262262
/// Searches the array for the first occurrence of a value and returns its index, or
263263
/// `None` if not found. Starts searching at index `from`; pass `None` to search the
264264
/// entire array.
265-
pub fn find(&self, value: Arg<$Element>, from: Option<usize>) -> Option<usize> {
265+
pub fn find(&self, value: impl AsArg<$Element>, from: Option<usize>) -> Option<usize> {
266266
let from = to_i64(from.unwrap_or(0));
267267
let index = self.as_inner().find(value.into_arg().into_packed_arg(), from);
268268
if index >= 0 {
@@ -275,7 +275,7 @@ macro_rules! impl_packed_array {
275275
/// Searches the array backwards for the last occurrence of a value and returns its
276276
/// index, or `None` if not found. Starts searching at index `from`; pass `None` to
277277
/// search the entire array.
278-
pub fn rfind(&self, value: Arg<$Element>, from: Option<usize>) -> Option<usize> {
278+
pub fn rfind(&self, value: impl AsArg<$Element>, from: Option<usize>) -> Option<usize> {
279279
let from = from.map(to_i64).unwrap_or(-1);
280280
let index = self.as_inner().rfind(value.into_arg().into_packed_arg(), from);
281281
// It's not documented, but `rfind` returns -1 if not found.
@@ -291,7 +291,7 @@ macro_rules! impl_packed_array {
291291
/// If the value is not present in the array, returns the insertion index that would maintain sorting order.
292292
///
293293
/// Calling `bsearch()` on an unsorted array results in unspecified (but safe) behavior.
294-
pub fn bsearch(&self, value: Arg<$Element>) -> usize {
294+
pub fn bsearch(&self, value: impl AsArg<$Element>) -> usize {
295295
to_usize(self.as_inner().bsearch(value.into_arg().into_packed_arg(), true))
296296
}
297297

godot-core/src/meta/as_arg.rs

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,29 @@ use std::ffi::CStr;
1414
/// An `impl AsArg<T>` parameter allows values to be passed which can be represented in the target type `T`. Note that unlike `From<T>`,
1515
/// this trait is implemented more conservatively.
1616
///
17+
/// As a result, `AsArg<T>` is currently only implemented for certain argument types:
18+
/// - `T` for by-value builtins (typically `Copy`): `i32`, `bool`, `Vector3`, `Transform2D`, ...
19+
/// - `&T` for by-ref builtins: `GString`, `Array`, `Dictionary`, `Packed*Array`, `Variant`...
20+
/// - `&str`, `&String` additionally for string types `GString`, `StringName`, `NodePath`.
21+
///
22+
/// # Pass by value
23+
/// Implicitly converting from `T` for by-ref builtins is explicitly not supported. This emphasizes that there is no need to consume the object,
24+
/// thus discourages unnecessary cloning.
25+
///
26+
/// If you need to pass owned values in generic code, you can use [`ArgTarget::value_to_arg()`].
27+
///
1728
/// # Performance for strings
1829
/// Godot has three string types: [`GString`], [`StringName`] and [`NodePath`]. Conversions between those three, as well as between `String` and
1930
/// them, is generally expensive because of allocations, re-encoding, validations, hashing, etc. While this doesn't matter for a few strings
2031
/// passed to engine APIs, it can become a problematic when passing long strings in a hot loop.
2132
///
22-
/// As a result, `AsArg<T>` is currently only implemented for certain conversions:
23-
/// - `&T` and `&mut T`, since those require no conversion or copy.
24-
/// - String literals like `"string"` and `c"string"`. While these _do_ need conversions, those are quite explicit, and
25-
/// `&'static CStr -> StringName` in particular is cheap.
33+
/// In the case of strings, we allow implicit conversion from Rust types `&str`, `&String` and `&'static CStr` (`StringName` only).
34+
/// While these conversions are not free, those are either explicit because a string literal is used, or they are unsurprising, because Godot
35+
/// cannot deal with raw Rust types. On the other hand, `GString` and `StringName` are sometimes used almost interchangeably (example:
36+
/// [`Node::set_name`](crate::classes::Node::set_name) takes `GString` but [`Node::get_name`](crate::classes::Node::get_name) returns `StringName`).
37+
///
38+
/// If you want to convert between Godot's string types for the sake of argument passing, each type provides an `arg()` method, such as
39+
/// [`GString::arg()`]. You cannot use this method in other contexts.
2640
#[diagnostic::on_unimplemented(
2741
message = "Argument of type `{Self}` cannot be passed to an `impl AsArg<{T}>` parameter",
2842
note = "If you pass by value, consider borrowing instead.",
@@ -34,7 +48,7 @@ where
3448
Self: Sized,
3549
{
3650
#[doc(hidden)]
37-
fn into_arg<'r>(self) -> <T as ArgTarget>::Type<'r>
51+
fn into_arg<'r>(self) -> <T as ArgTarget>::Arg<'r>
3852
where
3953
Self: 'r;
4054
}
@@ -76,20 +90,20 @@ macro_rules! arg_into_owned {
7690
macro_rules! impl_asarg_by_value {
7791
($T:ty) => {
7892
impl $crate::meta::AsArg<$T> for $T {
79-
fn into_arg<'r>(self) -> <$T as $crate::meta::ArgTarget>::Type<'r> {
93+
fn into_arg<'r>(self) -> <$T as $crate::meta::ArgTarget>::Arg<'r> {
8094
// Moves value (but typically a Copy type).
8195
self
8296
}
8397
}
8498

8599
impl $crate::meta::ArgTarget for $T {
86-
type Type<'v> = $T;
100+
type Arg<'v> = $T;
87101

88-
fn value_to_arg<'v>(self) -> Self::Type<'v> {
102+
fn value_to_arg<'v>(self) -> Self::Arg<'v> {
89103
self
90104
}
91105

92-
fn arg_to_ref<'r>(arg: &'r Self::Type<'_>) -> &'r Self {
106+
fn arg_to_ref<'r>(arg: &'r Self::Arg<'_>) -> &'r Self {
93107
arg
94108
}
95109
}
@@ -107,7 +121,7 @@ macro_rules! impl_asarg_by_ref {
107121
// Thus, keep `where` on same line.
108122
// type ArgType<'v> = &'v $T where Self: 'v;
109123

110-
fn into_arg<'cow>(self) -> <$T as $crate::meta::ArgTarget>::Type<'cow>
124+
fn into_arg<'cow>(self) -> <$T as $crate::meta::ArgTarget>::Arg<'cow>
111125
where
112126
'r: 'cow, // Original reference must be valid for at least as long as the returned cow.
113127
{
@@ -116,13 +130,13 @@ macro_rules! impl_asarg_by_ref {
116130
}
117131

118132
impl $crate::meta::ArgTarget for $T {
119-
type Type<'v> = $crate::meta::CowArg<'v, $T>;
133+
type Arg<'v> = $crate::meta::CowArg<'v, $T>;
120134

121-
fn value_to_arg<'v>(self) -> Self::Type<'v> {
135+
fn value_to_arg<'v>(self) -> Self::Arg<'v> {
122136
$crate::meta::CowArg::Owned(self)
123137
}
124138

125-
fn arg_to_ref<'r>(arg: &'r Self::Type<'_>) -> &'r Self {
139+
fn arg_to_ref<'r>(arg: &'r Self::Arg<'_>) -> &'r Self {
126140
arg.cow_as_ref()
127141
}
128142
}
@@ -136,11 +150,11 @@ macro_rules! declare_arg_method {
136150
///
137151
/// # Generic bounds
138152
/// The bounds are implementation-defined and may change at any time. Do not use this function in a generic context requiring `T`
139-
/// -- use the `From` trait in that case.
153+
/// -- use the `From` trait or [`ArgTarget`][crate::meta::ArgTarget] in that case.
140154
pub fn arg<T>(&self) -> impl $crate::meta::AsArg<T>
141155
where
142156
for<'a> T: From<&'a Self>
143-
+ $crate::meta::ArgTarget<Type<'a> = $crate::meta::CowArg<'a, T>>
157+
+ $crate::meta::ArgTarget<Arg<'a> = $crate::meta::CowArg<'a, T>>
144158
+ 'a,
145159
{
146160
$crate::meta::CowArg::Owned(T::from(self))
@@ -157,7 +171,7 @@ macro_rules! declare_arg_method {
157171
/// This is necessary for packed array dispatching to different "inner" backend signatures.
158172
impl<'a, T> AsArg<T> for CowArg<'a, T>
159173
where
160-
for<'r> T: ArgTarget<Type<'r> = CowArg<'r, T>> + 'r,
174+
for<'r> T: ArgTarget<Arg<'r> = CowArg<'r, T>> + 'r,
161175
{
162176
fn into_arg<'r>(self) -> CowArg<'r, T>
163177
where
@@ -228,32 +242,28 @@ impl AsArg<NodePath> for &String {
228242

229243
// ----------------------------------------------------------------------------------------------------------------------------------------------
230244

231-
/// Implemented for all types that can be stored in [`AsArg<T>`].
245+
/// Implemented for all parameter types `T` that are allowed to receive [impl `AsArg<T>`][AsArg].
232246
pub trait ArgTarget
233247
where
234248
Self: Sized,
235249
{
236-
/// Target type, either `T` or `CowArg<'v, T>`.
250+
/// Canonical argument passing type, either `T` or an internally-used CoW type.
237251
///
238252
/// The general rule is that `Copy` types are passed by value, while the rest is passed by reference.
239253
///
240-
/// This associated type is closely related to [`ToGodot::ToVia<'v>`] and may be reorganized.
241-
type Type<'v>: AsArg<Self>
254+
/// This associated type is closely related to [`ToGodot::ToVia<'v>`][crate::meta::ToGodot::ToVia] and may be reorganized.
255+
type Arg<'v>: AsArg<Self>
242256
where
243257
Self: 'v;
244258

245-
/// Converts an owned value to the canonical argument type.
259+
/// Converts an owned value to the canonical argument type, which can be passed to [`impl AsArg<T>`][AsArg].
246260
///
247261
/// Useful in generic contexts where only a value is available, and one doesn't want to dispatch between value/reference.
248-
#[doc(hidden)]
249-
fn value_to_arg<'v>(self) -> Self::Type<'v>;
262+
fn value_to_arg<'v>(self) -> Self::Arg<'v>;
250263

251-
/// Converts an owned value to the canonical argument type.
264+
/// Converts an argument to a shared reference.
252265
///
253-
/// Useful in generic contexts where only a value is available, and one doesn't want to dispatch between value/reference.
254-
#[doc(hidden)]
255-
fn arg_to_ref<'r>(arg: &'r Self::Type<'_>) -> &'r Self;
266+
/// Useful in generic contexts where you need to extract a reference of an argument, independently of how it is passed.
267+
#[doc(hidden)] // for now, users are encouraged to use only call-site of impl AsArg; declaration-site may still develop.
268+
fn arg_to_ref<'r>(arg: &'r Self::Arg<'_>) -> &'r Self;
256269
}
257-
258-
/// Shorthand to determine how a type is passed as an argument to Godot APIs.
259-
pub type Arg<'r, T> = <T as ArgTarget>::Type<'r>;

godot-core/src/obj/gd.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -782,13 +782,13 @@ impl<'r, T: GodotClass> AsArg<Gd<T>> for &'r Gd<T> {
782782
}
783783

784784
impl<T: GodotClass> ArgTarget for Gd<T> {
785-
type Type<'v> = CowArg<'v, Gd<T>>;
785+
type Arg<'v> = CowArg<'v, Gd<T>>;
786786

787-
fn value_to_arg<'v>(self) -> Self::Type<'v> {
787+
fn value_to_arg<'v>(self) -> Self::Arg<'v> {
788788
CowArg::Owned(self)
789789
}
790790

791-
fn arg_to_ref<'r>(arg: &'r Self::Type<'_>) -> &'r Self {
791+
fn arg_to_ref<'r>(arg: &'r Self::Arg<'_>) -> &'r Self {
792792
arg.cow_as_ref()
793793
}
794794
}
@@ -804,13 +804,13 @@ impl<'r, T: GodotClass> AsArg<Option<Gd<T>>> for Option<&'r Gd<T>> {
804804
}
805805

806806
impl<T: GodotClass> ArgTarget for Option<Gd<T>> {
807-
type Type<'v> = CowArg<'v, Option<Gd<T>>>;
807+
type Arg<'v> = CowArg<'v, Option<Gd<T>>>;
808808

809-
fn value_to_arg<'v>(self) -> Self::Type<'v> {
809+
fn value_to_arg<'v>(self) -> Self::Arg<'v> {
810810
CowArg::Owned(self)
811811
}
812812

813-
fn arg_to_ref<'r>(arg: &'r Self::Type<'_>) -> &'r Self {
813+
fn arg_to_ref<'r>(arg: &'r Self::Arg<'_>) -> &'r Self {
814814
arg.cow_as_ref()
815815
}
816816
}

0 commit comments

Comments
 (0)