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            fn op_bsearch(mut inner: Self::Inner<'_>, value: CowArg<'_, Self>, before: bool) -> i64 {
303                Self::with_arg(value, |arg| inner.bsearch(arg, before))
304            }
305
306            fn op_reverse(mut inner: Self::Inner<'_>) {
307                inner.reverse()
308            }
309
310            fn op_sort(mut inner: Self::Inner<'_>) {
311                inner.sort()
312            }
313
314            fn inner<'a>(array: &PackedArray<$Element>) -> Self::Inner<'a> {
315                crate::builtin::inner::$Inner::from_outer(array)
316            }
317
318            impl_packed_array_element!(@with_arg $ArgPass);
319        }
320    };
321
322    // Specialization for by-value/by-ref passing (only GString).
323    (@with_arg ByValue) => {
324        fn with_arg<F, R>(value: CowArg<'_, Self>, f: F) -> R
325        where
326            F: FnOnce(Self::Arg<'_>) -> R,
327        {
328            // into() allows conversions from u8|i32 -> i64 (Godot APIs take i64 even for Packed{Byte,Int32}Array).
329            f(value.cow_into_owned().into())
330        }
331    };
332
333    (@with_arg ByRef) => {
334        fn with_arg<F, R>(value: CowArg<'_, Self>, f: F) -> R
335        where
336            F: FnOnce(Self::Arg<'_>) -> R,
337        {
338            f(value.cow_as_ref())
339        }
340    };
341}
342
343// ----------------------------------------------------------------------------------------------------------------------------------------------
344// Concrete impls for different element types
345
346impl_packed_array_element!(
347    element_type: u8,
348    argument_type: i64,
349    argument_pass: ByValue,
350    indexed_type: u8,
351    variant_type: PACKED_BYTE_ARRAY,
352    inner_type: InnerPackedByteArray,
353    default_fn: packed_byte_array_construct_default,
354    copy_fn: packed_byte_array_construct_copy,
355    destroy_fn: packed_byte_array_destroy,
356    to_variant_fn: packed_byte_array_to_variant,
357    from_variant_fn: packed_byte_array_from_variant,
358    equals_fn: packed_byte_array_operator_equal,
359    index_mut_fn: packed_byte_array_operator_index,
360    index_const_fn: packed_byte_array_operator_index_const,
361);
362
363impl_packed_array_element!(
364    element_type: i32,
365    argument_type: i64,
366    argument_pass: ByValue,
367    indexed_type: i32,
368    variant_type: PACKED_INT32_ARRAY,
369    inner_type: InnerPackedInt32Array,
370    default_fn: packed_int32_array_construct_default,
371    copy_fn: packed_int32_array_construct_copy,
372    destroy_fn: packed_int32_array_destroy,
373    to_variant_fn: packed_int32_array_to_variant,
374    from_variant_fn: packed_int32_array_from_variant,
375    equals_fn: packed_int32_array_operator_equal,
376    index_mut_fn: packed_int32_array_operator_index,
377    index_const_fn: packed_int32_array_operator_index_const,
378);
379
380impl_packed_array_element!(
381    element_type: i64,
382    argument_type: i64,
383    argument_pass: ByValue,
384    indexed_type: i64,
385    variant_type: PACKED_INT64_ARRAY,
386    inner_type: InnerPackedInt64Array,
387    default_fn: packed_int64_array_construct_default,
388    copy_fn: packed_int64_array_construct_copy,
389    destroy_fn: packed_int64_array_destroy,
390    to_variant_fn: packed_int64_array_to_variant,
391    from_variant_fn: packed_int64_array_from_variant,
392    equals_fn: packed_int64_array_operator_equal,
393    index_mut_fn: packed_int64_array_operator_index,
394    index_const_fn: packed_int64_array_operator_index_const,
395);
396
397impl_packed_array_element!(
398    element_type: f32,
399    argument_type: f64,
400    argument_pass: ByValue,
401    indexed_type: f32,
402    variant_type: PACKED_FLOAT32_ARRAY,
403    inner_type: InnerPackedFloat32Array,
404    default_fn: packed_float32_array_construct_default,
405    copy_fn: packed_float32_array_construct_copy,
406    destroy_fn: packed_float32_array_destroy,
407    to_variant_fn: packed_float32_array_to_variant,
408    from_variant_fn: packed_float32_array_from_variant,
409    equals_fn: packed_float32_array_operator_equal,
410    index_mut_fn: packed_float32_array_operator_index,
411    index_const_fn: packed_float32_array_operator_index_const,
412);
413
414impl_packed_array_element!(
415    element_type: f64,
416    argument_type: f64,
417    argument_pass: ByValue,
418    indexed_type: f64,
419    variant_type: PACKED_FLOAT64_ARRAY,
420    inner_type: InnerPackedFloat64Array,
421    default_fn: packed_float64_array_construct_default,
422    copy_fn: packed_float64_array_construct_copy,
423    destroy_fn: packed_float64_array_destroy,
424    to_variant_fn: packed_float64_array_to_variant,
425    from_variant_fn: packed_float64_array_from_variant,
426    equals_fn: packed_float64_array_operator_equal,
427    index_mut_fn: packed_float64_array_operator_index,
428    index_const_fn: packed_float64_array_operator_index_const,
429);
430
431impl_packed_array_element!(
432    element_type: builtin::Vector2,
433    argument_type: builtin::Vector2,
434    argument_pass: ByValue,
435    indexed_type: sys::__GdextType,
436    variant_type: PACKED_VECTOR2_ARRAY,
437    inner_type: InnerPackedVector2Array,
438    default_fn: packed_vector2_array_construct_default,
439    copy_fn: packed_vector2_array_construct_copy,
440    destroy_fn: packed_vector2_array_destroy,
441    to_variant_fn: packed_vector2_array_to_variant,
442    from_variant_fn: packed_vector2_array_from_variant,
443    equals_fn: packed_vector2_array_operator_equal,
444    index_mut_fn: packed_vector2_array_operator_index,
445    index_const_fn: packed_vector2_array_operator_index_const,
446);
447
448impl_packed_array_element!(
449    element_type: builtin::Vector3,
450    argument_type: builtin::Vector3,
451    argument_pass: ByValue,
452    indexed_type: sys::__GdextType,
453    variant_type: PACKED_VECTOR3_ARRAY,
454    inner_type: InnerPackedVector3Array,
455    default_fn: packed_vector3_array_construct_default,
456    copy_fn: packed_vector3_array_construct_copy,
457    destroy_fn: packed_vector3_array_destroy,
458    to_variant_fn: packed_vector3_array_to_variant,
459    from_variant_fn: packed_vector3_array_from_variant,
460    equals_fn: packed_vector3_array_operator_equal,
461    index_mut_fn: packed_vector3_array_operator_index,
462    index_const_fn: packed_vector3_array_operator_index_const,
463);
464
465#[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
466impl_packed_array_element!(
467    element_type: builtin::Vector4,
468    argument_type: builtin::Vector4,
469    argument_pass: ByValue,
470    indexed_type: sys::__GdextType,
471    variant_type: PACKED_VECTOR4_ARRAY,
472    inner_type: InnerPackedVector4Array,
473    default_fn: packed_vector4_array_construct_default,
474    copy_fn: packed_vector4_array_construct_copy,
475    destroy_fn: packed_vector4_array_destroy,
476    to_variant_fn: packed_vector4_array_to_variant,
477    from_variant_fn: packed_vector4_array_from_variant,
478    equals_fn: packed_vector4_array_operator_equal,
479    index_mut_fn: packed_vector4_array_operator_index,
480    index_const_fn: packed_vector4_array_operator_index_const,
481);
482
483impl_packed_array_element!(
484    element_type: builtin::Color,
485    argument_type: builtin::Color,
486    argument_pass: ByValue,
487    indexed_type: sys::__GdextType,
488    variant_type: PACKED_COLOR_ARRAY,
489    inner_type: InnerPackedColorArray,
490    default_fn: packed_color_array_construct_default,
491    copy_fn: packed_color_array_construct_copy,
492    destroy_fn: packed_color_array_destroy,
493    to_variant_fn: packed_color_array_to_variant,
494    from_variant_fn: packed_color_array_from_variant,
495    equals_fn: packed_color_array_operator_equal,
496    index_mut_fn: packed_color_array_operator_index,
497    index_const_fn: packed_color_array_operator_index_const,
498);
499
500impl_packed_array_element!(
501    element_type: builtin::GString,
502    argument_type: &'a builtin::GString,
503    argument_pass: ByRef,
504    indexed_type: sys::__GdextString,
505    variant_type: PACKED_STRING_ARRAY,
506    inner_type: InnerPackedStringArray,
507    default_fn: packed_string_array_construct_default,
508    copy_fn: packed_string_array_construct_copy,
509    destroy_fn: packed_string_array_destroy,
510    to_variant_fn: packed_string_array_to_variant,
511    from_variant_fn: packed_string_array_from_variant,
512    equals_fn: packed_string_array_operator_equal,
513    index_mut_fn: packed_string_array_operator_index,
514    index_const_fn: packed_string_array_operator_index_const,
515);