Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_reflect/src/array.rs
9345 views
1
//! Traits and types used to power [array-like] operations via reflection.
2
//!
3
//! [array-like]: https://doc.rust-lang.org/book/ch03-02-data-types.html#the-array-type
4
use crate::generics::impl_generic_info_methods;
5
use crate::{
6
type_info::impl_type_methods, utility::reflect_hasher, ApplyError, Generics, MaybeTyped,
7
PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, Type, TypeInfo,
8
TypePath,
9
};
10
use alloc::{boxed::Box, vec::Vec};
11
use bevy_reflect_derive::impl_type_path;
12
use core::{
13
any::Any,
14
fmt::{Debug, Formatter},
15
hash::{Hash, Hasher},
16
};
17
18
/// A trait used to power [array-like] operations via [reflection].
19
///
20
/// This corresponds to true Rust arrays like `[T; N]`,
21
/// but also to any fixed-size linear sequence types.
22
/// It is expected that implementors of this trait uphold this contract
23
/// and maintain a fixed size as returned by the [`Array::len`] method.
24
///
25
/// Due to the [type-erasing] nature of the reflection API as a whole,
26
/// this trait does not make any guarantees that the implementor's elements
27
/// are homogeneous (i.e. all the same type).
28
///
29
/// This trait has a blanket implementation over Rust arrays of up to 32 items.
30
/// This implementation can technically contain more than 32,
31
/// but the blanket [`GetTypeRegistration`] is only implemented up to the 32
32
/// item limit due to a [limitation] on [`Deserialize`].
33
///
34
/// # Example
35
///
36
/// ```
37
/// use bevy_reflect::{PartialReflect, array::Array};
38
///
39
/// let foo: &dyn Array = &[123_u32, 456_u32, 789_u32];
40
/// assert_eq!(foo.len(), 3);
41
///
42
/// let field: &dyn PartialReflect = foo.get(0).unwrap();
43
/// assert_eq!(field.try_downcast_ref::<u32>(), Some(&123));
44
/// ```
45
///
46
/// [array-like]: https://doc.rust-lang.org/book/ch03-02-data-types.html#the-array-type
47
/// [reflection]: crate
48
/// [`List`]: crate::list::List
49
/// [type-erasing]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html
50
/// [`GetTypeRegistration`]: crate::GetTypeRegistration
51
/// [limitation]: https://github.com/serde-rs/serde/issues/1937
52
/// [`Deserialize`]: ::serde::Deserialize
53
pub trait Array: PartialReflect {
54
/// Returns a reference to the element at `index`, or `None` if out of bounds.
55
fn get(&self, index: usize) -> Option<&dyn PartialReflect>;
56
57
/// Returns a mutable reference to the element at `index`, or `None` if out of bounds.
58
fn get_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
59
60
/// Returns the number of elements in the array.
61
fn len(&self) -> usize;
62
63
/// Returns `true` if the collection contains no elements.
64
fn is_empty(&self) -> bool {
65
self.len() == 0
66
}
67
68
/// Returns an iterator over the array.
69
fn iter(&self) -> ArrayIter<'_>;
70
71
/// Drain the elements of this array to get a vector of owned values.
72
fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>>;
73
74
/// Creates a new [`DynamicArray`] from this array.
75
fn to_dynamic_array(&self) -> DynamicArray {
76
DynamicArray {
77
represented_type: self.get_represented_type_info(),
78
values: self.iter().map(PartialReflect::to_dynamic).collect(),
79
}
80
}
81
82
/// Will return `None` if [`TypeInfo`] is not available.
83
fn get_represented_array_info(&self) -> Option<&'static ArrayInfo> {
84
self.get_represented_type_info()?.as_array().ok()
85
}
86
}
87
88
/// A container for compile-time array info.
89
#[derive(Clone, Debug)]
90
pub struct ArrayInfo {
91
ty: Type,
92
generics: Generics,
93
item_info: fn() -> Option<&'static TypeInfo>,
94
item_ty: Type,
95
capacity: usize,
96
#[cfg(feature = "reflect_documentation")]
97
docs: Option<&'static str>,
98
}
99
100
impl ArrayInfo {
101
/// Create a new [`ArrayInfo`].
102
///
103
/// # Arguments
104
///
105
/// * `capacity`: The maximum capacity of the underlying array.
106
pub fn new<TArray: Array + TypePath, TItem: Reflect + MaybeTyped + TypePath>(
107
capacity: usize,
108
) -> Self {
109
Self {
110
ty: Type::of::<TArray>(),
111
generics: Generics::new(),
112
item_info: TItem::maybe_type_info,
113
item_ty: Type::of::<TItem>(),
114
capacity,
115
#[cfg(feature = "reflect_documentation")]
116
docs: None,
117
}
118
}
119
120
/// Sets the docstring for this array.
121
#[cfg(feature = "reflect_documentation")]
122
pub fn with_docs(self, docs: Option<&'static str>) -> Self {
123
Self { docs, ..self }
124
}
125
126
/// The compile-time capacity of the array.
127
pub fn capacity(&self) -> usize {
128
self.capacity
129
}
130
131
impl_type_methods!(ty);
132
133
/// The [`TypeInfo`] of the array item.
134
///
135
/// Returns `None` if the array item does not contain static type information,
136
/// such as for dynamic types.
137
pub fn item_info(&self) -> Option<&'static TypeInfo> {
138
(self.item_info)()
139
}
140
141
/// The [type] of the array item.
142
///
143
/// [type]: Type
144
pub fn item_ty(&self) -> Type {
145
self.item_ty
146
}
147
148
/// The docstring of this array, if any.
149
#[cfg(feature = "reflect_documentation")]
150
pub fn docs(&self) -> Option<&'static str> {
151
self.docs
152
}
153
154
impl_generic_info_methods!(generics);
155
}
156
157
/// A fixed-size list of reflected values.
158
///
159
/// This differs from [`DynamicList`] in that the size of the [`DynamicArray`]
160
/// is constant, whereas a [`DynamicList`] can have items added and removed.
161
///
162
/// This isn't to say that a [`DynamicArray`] is immutable— its items
163
/// can be mutated— just that the _number_ of items cannot change.
164
///
165
/// [`DynamicList`]: crate::list::DynamicList
166
#[derive(Debug)]
167
pub struct DynamicArray {
168
pub(crate) represented_type: Option<&'static TypeInfo>,
169
pub(crate) values: Box<[Box<dyn PartialReflect>]>,
170
}
171
172
impl DynamicArray {
173
/// Creates a new [`DynamicArray`].
174
#[inline]
175
pub fn new(values: Box<[Box<dyn PartialReflect>]>) -> Self {
176
Self {
177
represented_type: None,
178
values,
179
}
180
}
181
182
/// Sets the [type] to be represented by this `DynamicArray`.
183
///
184
/// # Panics
185
///
186
/// Panics if the given [type] is not a [`TypeInfo::Array`].
187
///
188
/// [type]: TypeInfo
189
pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
190
if let Some(represented_type) = represented_type {
191
assert!(
192
matches!(represented_type, TypeInfo::Array(_)),
193
"expected TypeInfo::Array but received: {represented_type:?}"
194
);
195
}
196
197
self.represented_type = represented_type;
198
}
199
}
200
201
impl PartialReflect for DynamicArray {
202
#[inline]
203
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
204
self.represented_type
205
}
206
207
#[inline]
208
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
209
self
210
}
211
212
#[inline]
213
fn as_partial_reflect(&self) -> &dyn PartialReflect {
214
self
215
}
216
217
#[inline]
218
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
219
self
220
}
221
222
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
223
Err(self)
224
}
225
226
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
227
None
228
}
229
230
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
231
None
232
}
233
234
fn apply(&mut self, value: &dyn PartialReflect) {
235
array_apply(self, value);
236
}
237
238
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
239
array_try_apply(self, value)
240
}
241
242
#[inline]
243
fn reflect_kind(&self) -> ReflectKind {
244
ReflectKind::Array
245
}
246
247
#[inline]
248
fn reflect_ref(&self) -> ReflectRef<'_> {
249
ReflectRef::Array(self)
250
}
251
252
#[inline]
253
fn reflect_mut(&mut self) -> ReflectMut<'_> {
254
ReflectMut::Array(self)
255
}
256
257
#[inline]
258
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
259
ReflectOwned::Array(self)
260
}
261
262
#[inline]
263
fn reflect_hash(&self) -> Option<u64> {
264
array_hash(self)
265
}
266
267
fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
268
array_partial_eq(self, value)
269
}
270
271
fn reflect_partial_cmp(&self, value: &dyn PartialReflect) -> Option<::core::cmp::Ordering> {
272
array_partial_cmp(self, value)
273
}
274
275
fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
276
write!(f, "DynamicArray(")?;
277
array_debug(self, f)?;
278
write!(f, ")")
279
}
280
281
#[inline]
282
fn is_dynamic(&self) -> bool {
283
true
284
}
285
}
286
287
impl Array for DynamicArray {
288
#[inline]
289
fn get(&self, index: usize) -> Option<&dyn PartialReflect> {
290
self.values.get(index).map(|value| &**value)
291
}
292
293
#[inline]
294
fn get_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
295
self.values.get_mut(index).map(|value| &mut **value)
296
}
297
298
#[inline]
299
fn len(&self) -> usize {
300
self.values.len()
301
}
302
303
#[inline]
304
fn iter(&self) -> ArrayIter<'_> {
305
ArrayIter::new(self)
306
}
307
308
#[inline]
309
fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>> {
310
self.values.into_vec()
311
}
312
}
313
314
impl FromIterator<Box<dyn PartialReflect>> for DynamicArray {
315
fn from_iter<I: IntoIterator<Item = Box<dyn PartialReflect>>>(values: I) -> Self {
316
Self {
317
represented_type: None,
318
values: values.into_iter().collect::<Vec<_>>().into_boxed_slice(),
319
}
320
}
321
}
322
323
impl<T: PartialReflect> FromIterator<T> for DynamicArray {
324
fn from_iter<I: IntoIterator<Item = T>>(values: I) -> Self {
325
values
326
.into_iter()
327
.map(|value| Box::new(value).into_partial_reflect())
328
.collect()
329
}
330
}
331
332
impl IntoIterator for DynamicArray {
333
type Item = Box<dyn PartialReflect>;
334
type IntoIter = alloc::vec::IntoIter<Self::Item>;
335
336
fn into_iter(self) -> Self::IntoIter {
337
self.values.into_vec().into_iter()
338
}
339
}
340
341
impl<'a> IntoIterator for &'a DynamicArray {
342
type Item = &'a dyn PartialReflect;
343
type IntoIter = ArrayIter<'a>;
344
345
fn into_iter(self) -> Self::IntoIter {
346
self.iter()
347
}
348
}
349
350
impl_type_path!((in bevy_reflect) DynamicArray);
351
352
/// An iterator over an [`Array`].
353
pub struct ArrayIter<'a> {
354
array: &'a dyn Array,
355
index: usize,
356
}
357
358
impl ArrayIter<'_> {
359
/// Creates a new [`ArrayIter`].
360
#[inline]
361
pub const fn new(array: &dyn Array) -> ArrayIter<'_> {
362
ArrayIter { array, index: 0 }
363
}
364
}
365
366
impl<'a> Iterator for ArrayIter<'a> {
367
type Item = &'a dyn PartialReflect;
368
369
#[inline]
370
fn next(&mut self) -> Option<Self::Item> {
371
let value = self.array.get(self.index);
372
self.index += value.is_some() as usize;
373
value
374
}
375
376
#[inline]
377
fn size_hint(&self) -> (usize, Option<usize>) {
378
let size = self.array.len();
379
(size, Some(size))
380
}
381
}
382
383
impl<'a> ExactSizeIterator for ArrayIter<'a> {}
384
385
/// Returns the `u64` hash of the given [array](Array).
386
#[inline]
387
pub fn array_hash<A: Array + ?Sized>(array: &A) -> Option<u64> {
388
let mut hasher = reflect_hasher();
389
Any::type_id(array).hash(&mut hasher);
390
array.len().hash(&mut hasher);
391
for value in array.iter() {
392
hasher.write_u64(value.reflect_hash()?);
393
}
394
Some(hasher.finish())
395
}
396
397
/// Applies the reflected [array](Array) data to the given [array](Array).
398
///
399
/// # Panics
400
///
401
/// * Panics if the two arrays have differing lengths.
402
/// * Panics if the reflected value is not a [valid array](ReflectRef::Array).
403
#[inline]
404
pub fn array_apply<A: Array + ?Sized>(array: &mut A, reflect: &dyn PartialReflect) {
405
if let ReflectRef::Array(reflect_array) = reflect.reflect_ref() {
406
if array.len() != reflect_array.len() {
407
panic!("Attempted to apply different sized `Array` types.");
408
}
409
for (i, value) in reflect_array.iter().enumerate() {
410
let v = array.get_mut(i).unwrap();
411
v.apply(value);
412
}
413
} else {
414
panic!("Attempted to apply a non-`Array` type to an `Array` type.");
415
}
416
}
417
418
/// Tries to apply the reflected [array](Array) data to the given [array](Array) and
419
/// returns a Result.
420
///
421
/// # Errors
422
///
423
/// * Returns an [`ApplyError::DifferentSize`] if the two arrays have differing lengths.
424
/// * Returns an [`ApplyError::MismatchedKinds`] if the reflected value is not a
425
/// [valid array](ReflectRef::Array).
426
/// * Returns any error that is generated while applying elements to each other.
427
#[inline]
428
pub fn array_try_apply<A: Array>(
429
array: &mut A,
430
reflect: &dyn PartialReflect,
431
) -> Result<(), ApplyError> {
432
let reflect_array = reflect.reflect_ref().as_array()?;
433
434
if array.len() != reflect_array.len() {
435
return Err(ApplyError::DifferentSize {
436
from_size: reflect_array.len(),
437
to_size: array.len(),
438
});
439
}
440
441
for (i, value) in reflect_array.iter().enumerate() {
442
let v = array.get_mut(i).unwrap();
443
v.try_apply(value)?;
444
}
445
446
Ok(())
447
}
448
449
/// Compares two [arrays](Array) (one concrete and one reflected) to see if they
450
/// are equal.
451
///
452
/// Returns [`None`] if the comparison couldn't even be performed.
453
#[inline]
454
pub fn array_partial_eq<A: Array + ?Sized>(
455
array: &A,
456
reflect: &dyn PartialReflect,
457
) -> Option<bool> {
458
match reflect.reflect_ref() {
459
ReflectRef::Array(reflect_array) if reflect_array.len() == array.len() => {
460
for (a, b) in array.iter().zip(reflect_array.iter()) {
461
let eq_result = a.reflect_partial_eq(b);
462
if let failed @ (Some(false) | None) = eq_result {
463
return failed;
464
}
465
}
466
}
467
_ => return Some(false),
468
}
469
470
Some(true)
471
}
472
473
/// Lexicographically compares two [arrays](Array) and returns their ordering.
474
///
475
/// Returns [`None`] if the comparison couldn't be performed (e.g., kinds mismatch
476
/// or an element comparison returns `None`).
477
#[inline]
478
pub fn array_partial_cmp<A: Array + ?Sized>(
479
array: &A,
480
reflect: &dyn PartialReflect,
481
) -> Option<::core::cmp::Ordering> {
482
let ReflectRef::Array(reflect_array) = reflect.reflect_ref() else {
483
return None;
484
};
485
486
let min_len = core::cmp::min(array.len(), reflect_array.len());
487
488
for (a, b) in array.iter().zip(reflect_array.iter()).take(min_len) {
489
match a.reflect_partial_cmp(b) {
490
None => return None,
491
Some(core::cmp::Ordering::Equal) => continue,
492
Some(ord) => return Some(ord),
493
}
494
}
495
496
// If all compared elements were equal, order by length
497
Some(array.len().cmp(&reflect_array.len()))
498
}
499
500
/// The default debug formatter for [`Array`] types.
501
///
502
/// # Example
503
/// ```
504
/// use bevy_reflect::Reflect;
505
///
506
/// let my_array: &dyn Reflect = &[1, 2, 3];
507
/// println!("{:#?}", my_array);
508
///
509
/// // Output:
510
///
511
/// // [
512
/// // 1,
513
/// // 2,
514
/// // 3,
515
/// // ]
516
/// ```
517
#[inline]
518
pub fn array_debug(dyn_array: &dyn Array, f: &mut Formatter<'_>) -> core::fmt::Result {
519
let mut debug = f.debug_list();
520
for item in dyn_array.iter() {
521
debug.entry(&item as &dyn Debug);
522
}
523
debug.finish()
524
}
525
#[cfg(test)]
526
mod tests {
527
use crate::Reflect;
528
use alloc::boxed::Box;
529
530
#[test]
531
fn next_index_increment() {
532
const SIZE: usize = if cfg!(debug_assertions) {
533
4
534
} else {
535
// If compiled in release mode, verify we dont overflow
536
usize::MAX
537
};
538
539
let b = Box::new([(); SIZE]).into_reflect();
540
541
let array = b.reflect_ref().as_array().unwrap();
542
543
let mut iter = array.iter();
544
iter.index = SIZE - 1;
545
assert!(iter.next().is_some());
546
547
// When None we should no longer increase index
548
assert!(iter.next().is_none());
549
assert!(iter.index == SIZE);
550
assert!(iter.next().is_none());
551
assert!(iter.index == SIZE);
552
}
553
}
554
555