godot_core/builtin/collections/
packed_array_element.rs

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
8use sys::{interface_fn, GodotFfi, SysPtr};
9
10use crate::builtin::collections::extend_buffer::{ExtendBuffer, ExtendBufferTrait};
11use crate::builtin::PackedArray;
12use crate::meta::signed_range::SignedRange;
13use crate::meta::{CowArg, FromGodot, GodotType, ToGodot};
14use crate::registry::property::builtin_type_string;
15use crate::{builtin, sys};
16
17/// Marker trait to identify types that can be stored in [`PackedArray<T>`][crate::builtin::PackedArray].
18#[diagnostic::on_unimplemented(
19    message = "`PackedArray<T>` can only store element types supported in Godot packed arrays.",
20    label = "has invalid element type"
21)]
22// FromGodot isn't used, but can come in handy as an implied bound.
23// ToGodot is needed for AsArg<T>.
24pub trait PackedArrayElement: GodotType + Clone + ToGodot + FromGodot {
25    /// Element variant type.
26    #[doc(hidden)]
27    const VARIANT_TYPE: sys::VariantType;
28
29    /// Code-generated inner type, e.g. `InnerPackedStringArray`.
30    #[doc(hidden)]
31    type Inner<'a>;
32
33    /// The type used for function arguments when passing elements, e.g. `&'a GString` or `i64`.
34    #[doc(hidden)]
35    type Arg<'a>;
36
37    /// The pointee type returned from FFI index operations, e.g. `i64` or `sys::__GdextString` (opaque type behind `GDExtensionTypePtr`).
38    #[doc(hidden)]
39    type Indexed;
40
41    /// ExtendBuffer type with appropriate capacity `N` for this element type.
42    #[doc(hidden)]
43    type ExtendBuffer: Default + ExtendBufferTrait<Self>;
44
45    // ----------------------------------------------------------------------------------------------------------------------------------------------
46    // Property-related API
47
48    /// See [`crate::meta::traits::ArrayElement::element_type_string()`].
49    #[doc(hidden)]
50    fn element_type_string() -> String {
51        builtin_type_string::<Self>()
52    }
53
54    // ----------------------------------------------------------------------------------------------------------------------------------------------
55    // FFI operations
56
57    #[doc(hidden)]
58    unsafe fn ffi_to_variant(
59        type_ptr: sys::GDExtensionConstTypePtr,
60        variant_ptr: sys::GDExtensionVariantPtr,
61    );
62
63    #[doc(hidden)]
64    unsafe fn ffi_from_variant(
65        variant_ptr: sys::GDExtensionConstVariantPtr,
66        type_ptr: sys::GDExtensionTypePtr,
67    );
68
69    #[doc(hidden)]
70    unsafe fn ffi_default(type_ptr: sys::GDExtensionTypePtr);
71
72    #[doc(hidden)]
73    unsafe fn ffi_copy(src_ptr: sys::GDExtensionConstTypePtr, dst_ptr: sys::GDExtensionTypePtr);
74
75    #[doc(hidden)]
76    unsafe fn ffi_destroy(type_ptr: sys::GDExtensionTypePtr);
77
78    #[doc(hidden)]
79    unsafe fn ffi_equals(
80        left_ptr: sys::GDExtensionConstTypePtr,
81        right_ptr: sys::GDExtensionConstTypePtr,
82    ) -> bool;
83
84    #[doc(hidden)]
85    unsafe fn ffi_index_const(
86        type_ptr: sys::GDExtensionConstTypePtr,
87        index: i64,
88    ) -> *const Self::Indexed;
89
90    #[doc(hidden)]
91    unsafe fn ffi_index_mut(type_ptr: sys::GDExtensionTypePtr, index: i64) -> *mut Self::Indexed;
92
93    // ----------------------------------------------------------------------------------------------------------------------------------------------
94    // Delegates to inner Packed*Array API
95
96    #[doc(hidden)]
97    fn op_has(inner: Self::Inner<'_>, value: CowArg<'_, Self>) -> bool;
98
99    #[doc(hidden)]
100    fn op_count(inner: Self::Inner<'_>, value: CowArg<'_, Self>) -> i64;
101
102    #[doc(hidden)]
103    fn op_size(inner: Self::Inner<'_>) -> i64;
104
105    #[doc(hidden)]
106    fn op_is_empty(inner: Self::Inner<'_>) -> bool;
107
108    #[doc(hidden)]
109    fn op_clear(inner: Self::Inner<'_>);
110
111    #[doc(hidden)]
112    fn op_push_back(inner: Self::Inner<'_>, value: CowArg<'_, Self>);
113
114    #[doc(hidden)]
115    fn op_insert(inner: Self::Inner<'_>, index: i64, value: CowArg<'_, Self>);
116
117    #[doc(hidden)]
118    fn op_remove_at(inner: Self::Inner<'_>, index: i64);
119
120    #[doc(hidden)]
121    fn op_fill(inner: Self::Inner<'_>, value: CowArg<'_, Self>);
122
123    #[doc(hidden)]
124    fn op_resize(inner: Self::Inner<'_>, size: i64);
125
126    #[doc(hidden)]
127    fn op_append_array(inner: Self::Inner<'_>, other: &PackedArray<Self>);
128
129    #[doc(hidden)]
130    fn op_slice(inner: Self::Inner<'_>, range: impl SignedRange) -> PackedArray<Self>;
131
132    #[doc(hidden)]
133    fn op_find(inner: Self::Inner<'_>, value: CowArg<'_, Self>, from: i64) -> i64;
134
135    #[doc(hidden)]
136    fn op_rfind(inner: Self::Inner<'_>, value: CowArg<'_, Self>, from: i64) -> i64;
137
138    #[doc(hidden)]
139    fn op_bsearch(inner: Self::Inner<'_>, value: CowArg<'_, Self>, before: bool) -> i64;
140
141    #[doc(hidden)]
142    fn op_reverse(inner: Self::Inner<'_>);
143
144    #[doc(hidden)]
145    fn op_sort(inner: Self::Inner<'_>);
146
147    #[doc(hidden)]
148    fn inner<'a>(array: &PackedArray<Self>) -> Self::Inner<'a>;
149
150    /// Call inner function with an element-type argument.
151    ///
152    /// Has this functional design for a reason: to pass `CowArg` as either value or ref, it needs to be consumed. However we can then not
153    /// return a reference, as the `CowArg` would be dropped inside the function.
154    #[doc(hidden)]
155    fn with_arg<F, R>(value: CowArg<'_, Self>, f: F) -> R
156    where
157        F: FnOnce(Self::Arg<'_>) -> R;
158}
159
160/// Helper because `usize::max()` is not const.
161const fn const_max(a: usize, b: usize) -> usize {
162    if a > b {
163        a
164    } else {
165        b
166    }
167}
168
169// ----------------------------------------------------------------------------------------------------------------------------------------------
170// Macro to implement the spec for a concrete element type
171
172macro_rules! impl_packed_array_element {
173    (
174        element_type: $Element:ty,
175        argument_type: $Arg:ty,
176        argument_pass: $ArgPass:ident,
177        indexed_type: $IndexRetType:ty,
178        variant_type: $VariantType:ident,
179        inner_type: $Inner:ident,
180        default_fn: $default_fn:ident,
181        copy_fn: $copy_fn:ident,
182        destroy_fn: $destroy_fn:ident,
183        to_variant_fn: $to_variant_fn:ident,
184        from_variant_fn: $from_variant_fn:ident,
185        equals_fn: $equals_fn:ident,
186        index_mut_fn: $index_mut_fn:ident,
187        index_const_fn: $index_const_fn:ident,
188    ) => {
189        impl PackedArrayElement for $Element {
190            const VARIANT_TYPE: sys::VariantType = sys::VariantType::$VariantType;
191
192            type Inner<'a> = crate::builtin::inner::$Inner<'a>;
193            type Arg<'a> = $Arg;
194            type Indexed = $IndexRetType;
195            type ExtendBuffer = ExtendBuffer<$Element, {
196                const_max(1, 2048 / std::mem::size_of::<$Element>())
197            }>;
198
199            unsafe fn ffi_default(type_ptr: sys::GDExtensionTypePtr) {
200                let constructor = sys::builtin_fn!($default_fn);
201                constructor(SysPtr::as_uninit(type_ptr), std::ptr::null_mut());
202            }
203
204            unsafe fn ffi_copy(src_ptr: sys::GDExtensionConstTypePtr, dst_ptr: sys::GDExtensionTypePtr) {
205                let constructor = sys::builtin_fn!($copy_fn);
206                let args = [src_ptr];
207                constructor(SysPtr::as_uninit(dst_ptr), args.as_ptr());
208            }
209
210            unsafe fn ffi_destroy(type_ptr: sys::GDExtensionTypePtr) {
211                let destructor = sys::builtin_fn!($destroy_fn @1);
212                destructor(type_ptr);
213            }
214
215            unsafe fn ffi_to_variant(type_ptr: sys::GDExtensionConstTypePtr, variant_ptr: sys::GDExtensionVariantPtr) {
216                let converter = sys::builtin_fn!($to_variant_fn);
217                converter(SysPtr::as_uninit(variant_ptr), SysPtr::force_mut(type_ptr));
218            }
219
220            unsafe fn ffi_from_variant(variant_ptr: sys::GDExtensionConstVariantPtr, type_ptr: sys::GDExtensionTypePtr) {
221                let converter = sys::builtin_fn!($from_variant_fn);
222                converter(SysPtr::as_uninit(type_ptr), SysPtr::force_mut(variant_ptr));
223            }
224
225            unsafe fn ffi_equals(left_ptr: sys::GDExtensionConstTypePtr, right_ptr: sys::GDExtensionConstTypePtr) -> bool {
226                let mut result = false;
227                sys::builtin_call! {
228                    $equals_fn(left_ptr, right_ptr, result.sys_mut())
229                };
230                result
231            }
232
233            unsafe fn ffi_index_const(type_ptr: sys::GDExtensionConstTypePtr, index: i64) -> *const Self::Indexed {
234                unsafe {
235                    interface_fn!($index_const_fn)(type_ptr, index)
236                }
237            }
238
239            unsafe fn ffi_index_mut(type_ptr: sys::GDExtensionTypePtr, index: i64) -> *mut Self::Indexed {
240                unsafe {
241                    interface_fn!($index_mut_fn)(type_ptr, index)
242                }
243            }
244
245            fn op_has(inner: Self::Inner<'_>, value: CowArg<'_, Self>) -> bool {
246                Self::with_arg(value, |arg| inner.has(arg))
247            }
248
249            fn op_count(inner: Self::Inner<'_>, value: CowArg<'_, Self>) -> i64 {
250                Self::with_arg(value, |arg| inner.count(arg))
251            }
252
253            fn op_size(inner: Self::Inner<'_>) -> i64 {
254                inner.size()
255            }
256
257            fn op_is_empty(inner: Self::Inner<'_>) -> bool {
258                inner.is_empty()
259            }
260
261            fn op_clear(mut inner: Self::Inner<'_>) {
262                inner.clear();
263            }
264
265            fn op_push_back(mut inner: Self::Inner<'_>, value: CowArg<'_, Self>) {
266                Self::with_arg(value, |arg| inner.push_back(arg));
267            }
268
269            fn op_insert(mut inner: Self::Inner<'_>, index: i64, value: CowArg<'_, Self>) {
270                Self::with_arg(value, |arg| inner.insert(index, arg));
271            }
272
273            fn op_remove_at(mut inner: Self::Inner<'_>, index: i64) {
274                inner.remove_at(index);
275            }
276
277            fn op_fill(mut inner: Self::Inner<'_>, value: CowArg<'_, Self>) {
278                Self::with_arg(value, |arg| inner.fill(arg));
279            }
280
281            fn op_resize(mut inner: Self::Inner<'_>, size: i64) {
282                inner.resize(size);
283            }
284
285            fn op_append_array(mut inner: Self::Inner<'_>, other: &PackedArray<Self>) {
286                inner.append_array(other);
287            }
288
289            fn op_slice(inner: Self::Inner<'_>, range: impl $crate::meta::signed_range::SignedRange) -> PackedArray<Self> {
290                let (begin, end) = range.signed();
291                inner.slice(begin, end.unwrap_or(i32::MAX as i64))
292            }
293
294            fn op_find(inner: Self::Inner<'_>, value: CowArg<'_, Self>, from: i64) -> i64 {
295                Self::with_arg(value, |arg| inner.find(arg, from))
296            }
297
298            fn op_rfind(inner: Self::Inner<'_>, value: CowArg<'_, Self>, from: i64) -> i64 {
299                Self::with_arg(value, |arg| inner.rfind(arg, from))
300            }
301
302            #[allow(unused_mut)] // Generated bsearch() needs &mut before 4.6, but not anymore afterwards.
303            fn op_bsearch(mut inner: Self::Inner<'_>, value: CowArg<'_, Self>, before: bool) -> i64 {
304                Self::with_arg(value, |arg| inner.bsearch(arg, before))
305            }
306
307            fn op_reverse(mut inner: Self::Inner<'_>) {
308                inner.reverse()
309            }
310
311            fn op_sort(mut inner: Self::Inner<'_>) {
312                inner.sort()
313            }
314
315            fn inner<'a>(array: &PackedArray<$Element>) -> Self::Inner<'a> {
316                crate::builtin::inner::$Inner::from_outer(array)
317            }
318
319            impl_packed_array_element!(@with_arg $ArgPass);
320        }
321    };
322
323    // Specialization for by-value/by-ref passing (only GString).
324    (@with_arg ByValue) => {
325        fn with_arg<F, R>(value: CowArg<'_, Self>, f: F) -> R
326        where
327            F: FnOnce(Self::Arg<'_>) -> R,
328        {
329            // into() allows conversions from u8|i32 -> i64 (Godot APIs take i64 even for Packed{Byte,Int32}Array).
330            f(value.cow_into_owned().into())
331        }
332    };
333
334    (@with_arg ByRef) => {
335        fn with_arg<F, R>(value: CowArg<'_, Self>, f: F) -> R
336        where
337            F: FnOnce(Self::Arg<'_>) -> R,
338        {
339            f(value.cow_as_ref())
340        }
341    };
342}
343
344// ----------------------------------------------------------------------------------------------------------------------------------------------
345// Concrete impls for different element types
346
347impl_packed_array_element!(
348    element_type: u8,
349    argument_type: i64,
350    argument_pass: ByValue,
351    indexed_type: u8,
352    variant_type: PACKED_BYTE_ARRAY,
353    inner_type: InnerPackedByteArray,
354    default_fn: packed_byte_array_construct_default,
355    copy_fn: packed_byte_array_construct_copy,
356    destroy_fn: packed_byte_array_destroy,
357    to_variant_fn: packed_byte_array_to_variant,
358    from_variant_fn: packed_byte_array_from_variant,
359    equals_fn: packed_byte_array_operator_equal,
360    index_mut_fn: packed_byte_array_operator_index,
361    index_const_fn: packed_byte_array_operator_index_const,
362);
363
364impl_packed_array_element!(
365    element_type: i32,
366    argument_type: i64,
367    argument_pass: ByValue,
368    indexed_type: i32,
369    variant_type: PACKED_INT32_ARRAY,
370    inner_type: InnerPackedInt32Array,
371    default_fn: packed_int32_array_construct_default,
372    copy_fn: packed_int32_array_construct_copy,
373    destroy_fn: packed_int32_array_destroy,
374    to_variant_fn: packed_int32_array_to_variant,
375    from_variant_fn: packed_int32_array_from_variant,
376    equals_fn: packed_int32_array_operator_equal,
377    index_mut_fn: packed_int32_array_operator_index,
378    index_const_fn: packed_int32_array_operator_index_const,
379);
380
381impl_packed_array_element!(
382    element_type: i64,
383    argument_type: i64,
384    argument_pass: ByValue,
385    indexed_type: i64,
386    variant_type: PACKED_INT64_ARRAY,
387    inner_type: InnerPackedInt64Array,
388    default_fn: packed_int64_array_construct_default,
389    copy_fn: packed_int64_array_construct_copy,
390    destroy_fn: packed_int64_array_destroy,
391    to_variant_fn: packed_int64_array_to_variant,
392    from_variant_fn: packed_int64_array_from_variant,
393    equals_fn: packed_int64_array_operator_equal,
394    index_mut_fn: packed_int64_array_operator_index,
395    index_const_fn: packed_int64_array_operator_index_const,
396);
397
398impl_packed_array_element!(
399    element_type: f32,
400    argument_type: f64,
401    argument_pass: ByValue,
402    indexed_type: f32,
403    variant_type: PACKED_FLOAT32_ARRAY,
404    inner_type: InnerPackedFloat32Array,
405    default_fn: packed_float32_array_construct_default,
406    copy_fn: packed_float32_array_construct_copy,
407    destroy_fn: packed_float32_array_destroy,
408    to_variant_fn: packed_float32_array_to_variant,
409    from_variant_fn: packed_float32_array_from_variant,
410    equals_fn: packed_float32_array_operator_equal,
411    index_mut_fn: packed_float32_array_operator_index,
412    index_const_fn: packed_float32_array_operator_index_const,
413);
414
415impl_packed_array_element!(
416    element_type: f64,
417    argument_type: f64,
418    argument_pass: ByValue,
419    indexed_type: f64,
420    variant_type: PACKED_FLOAT64_ARRAY,
421    inner_type: InnerPackedFloat64Array,
422    default_fn: packed_float64_array_construct_default,
423    copy_fn: packed_float64_array_construct_copy,
424    destroy_fn: packed_float64_array_destroy,
425    to_variant_fn: packed_float64_array_to_variant,
426    from_variant_fn: packed_float64_array_from_variant,
427    equals_fn: packed_float64_array_operator_equal,
428    index_mut_fn: packed_float64_array_operator_index,
429    index_const_fn: packed_float64_array_operator_index_const,
430);
431
432impl_packed_array_element!(
433    element_type: builtin::Vector2,
434    argument_type: builtin::Vector2,
435    argument_pass: ByValue,
436    indexed_type: sys::__GdextType,
437    variant_type: PACKED_VECTOR2_ARRAY,
438    inner_type: InnerPackedVector2Array,
439    default_fn: packed_vector2_array_construct_default,
440    copy_fn: packed_vector2_array_construct_copy,
441    destroy_fn: packed_vector2_array_destroy,
442    to_variant_fn: packed_vector2_array_to_variant,
443    from_variant_fn: packed_vector2_array_from_variant,
444    equals_fn: packed_vector2_array_operator_equal,
445    index_mut_fn: packed_vector2_array_operator_index,
446    index_const_fn: packed_vector2_array_operator_index_const,
447);
448
449impl_packed_array_element!(
450    element_type: builtin::Vector3,
451    argument_type: builtin::Vector3,
452    argument_pass: ByValue,
453    indexed_type: sys::__GdextType,
454    variant_type: PACKED_VECTOR3_ARRAY,
455    inner_type: InnerPackedVector3Array,
456    default_fn: packed_vector3_array_construct_default,
457    copy_fn: packed_vector3_array_construct_copy,
458    destroy_fn: packed_vector3_array_destroy,
459    to_variant_fn: packed_vector3_array_to_variant,
460    from_variant_fn: packed_vector3_array_from_variant,
461    equals_fn: packed_vector3_array_operator_equal,
462    index_mut_fn: packed_vector3_array_operator_index,
463    index_const_fn: packed_vector3_array_operator_index_const,
464);
465
466#[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
467impl_packed_array_element!(
468    element_type: builtin::Vector4,
469    argument_type: builtin::Vector4,
470    argument_pass: ByValue,
471    indexed_type: sys::__GdextType,
472    variant_type: PACKED_VECTOR4_ARRAY,
473    inner_type: InnerPackedVector4Array,
474    default_fn: packed_vector4_array_construct_default,
475    copy_fn: packed_vector4_array_construct_copy,
476    destroy_fn: packed_vector4_array_destroy,
477    to_variant_fn: packed_vector4_array_to_variant,
478    from_variant_fn: packed_vector4_array_from_variant,
479    equals_fn: packed_vector4_array_operator_equal,
480    index_mut_fn: packed_vector4_array_operator_index,
481    index_const_fn: packed_vector4_array_operator_index_const,
482);
483
484impl_packed_array_element!(
485    element_type: builtin::Color,
486    argument_type: builtin::Color,
487    argument_pass: ByValue,
488    indexed_type: sys::__GdextType,
489    variant_type: PACKED_COLOR_ARRAY,
490    inner_type: InnerPackedColorArray,
491    default_fn: packed_color_array_construct_default,
492    copy_fn: packed_color_array_construct_copy,
493    destroy_fn: packed_color_array_destroy,
494    to_variant_fn: packed_color_array_to_variant,
495    from_variant_fn: packed_color_array_from_variant,
496    equals_fn: packed_color_array_operator_equal,
497    index_mut_fn: packed_color_array_operator_index,
498    index_const_fn: packed_color_array_operator_index_const,
499);
500
501impl_packed_array_element!(
502    element_type: builtin::GString,
503    argument_type: &'a builtin::GString,
504    argument_pass: ByRef,
505    indexed_type: sys::__GdextString,
506    variant_type: PACKED_STRING_ARRAY,
507    inner_type: InnerPackedStringArray,
508    default_fn: packed_string_array_construct_default,
509    copy_fn: packed_string_array_construct_copy,
510    destroy_fn: packed_string_array_destroy,
511    to_variant_fn: packed_string_array_to_variant,
512    from_variant_fn: packed_string_array_from_variant,
513    equals_fn: packed_string_array_operator_equal,
514    index_mut_fn: packed_string_array_operator_index,
515    index_const_fn: packed_string_array_operator_index_const,
516);