Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_reflect/src/func/args/list.rs
6600 views
1
use crate::{
2
func::{
3
args::{Arg, ArgValue, FromArg},
4
ArgError,
5
},
6
PartialReflect, Reflect, TypePath,
7
};
8
use alloc::{
9
boxed::Box,
10
collections::vec_deque::{Iter, VecDeque},
11
};
12
13
/// A list of arguments that can be passed to a [`DynamicFunction`] or [`DynamicFunctionMut`].
14
///
15
/// # Example
16
///
17
/// ```
18
/// # use bevy_reflect::func::{ArgValue, ArgList};
19
/// let foo = 123;
20
/// let bar = 456;
21
/// let mut baz = 789;
22
/// let args = ArgList::new()
23
/// // Push an owned argument
24
/// .with_owned(foo)
25
/// // Push an owned and boxed argument
26
/// .with_boxed(Box::new(foo))
27
/// // Push a reference argument
28
/// .with_ref(&bar)
29
/// // Push a mutable reference argument
30
/// .with_mut(&mut baz)
31
/// // Push a manually constructed argument
32
/// .with_arg(ArgValue::Ref(&3.14));
33
/// ```
34
///
35
/// [arguments]: Arg
36
/// [`DynamicFunction`]: crate::func::DynamicFunction
37
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
38
#[derive(Default, Debug)]
39
pub struct ArgList<'a> {
40
list: VecDeque<Arg<'a>>,
41
/// A flag that indicates if the list needs to be re-indexed.
42
///
43
/// This flag should be set when an argument is removed from the beginning of the list,
44
/// so that any future push operations will re-index the arguments.
45
needs_reindex: bool,
46
}
47
48
impl<'a> ArgList<'a> {
49
/// Create a new empty list of arguments.
50
pub fn new() -> Self {
51
Self {
52
list: VecDeque::new(),
53
needs_reindex: false,
54
}
55
}
56
57
/// Push an [`ArgValue`] onto the list.
58
///
59
/// If an argument was previously removed from the beginning of the list,
60
/// this method will also re-index the list.
61
pub fn push_arg(&mut self, arg: ArgValue<'a>) {
62
if self.needs_reindex {
63
for (index, arg) in self.list.iter_mut().enumerate() {
64
arg.set_index(index);
65
}
66
self.needs_reindex = false;
67
}
68
69
let index = self.list.len();
70
self.list.push_back(Arg::new(index, arg));
71
}
72
73
/// Push an [`ArgValue::Ref`] onto the list with the given reference.
74
///
75
/// If an argument was previously removed from the beginning of the list,
76
/// this method will also re-index the list.
77
pub fn push_ref(&mut self, arg: &'a dyn PartialReflect) {
78
self.push_arg(ArgValue::Ref(arg));
79
}
80
81
/// Push an [`ArgValue::Mut`] onto the list with the given mutable reference.
82
///
83
/// If an argument was previously removed from the beginning of the list,
84
/// this method will also re-index the list.
85
pub fn push_mut(&mut self, arg: &'a mut dyn PartialReflect) {
86
self.push_arg(ArgValue::Mut(arg));
87
}
88
89
/// Push an [`ArgValue::Owned`] onto the list with the given owned value.
90
///
91
/// If an argument was previously removed from the beginning of the list,
92
/// this method will also re-index the list.
93
pub fn push_owned(&mut self, arg: impl PartialReflect) {
94
self.push_arg(ArgValue::Owned(Box::new(arg)));
95
}
96
97
/// Push an [`ArgValue::Owned`] onto the list with the given boxed value.
98
///
99
/// If an argument was previously removed from the beginning of the list,
100
/// this method will also re-index the list.
101
pub fn push_boxed(&mut self, arg: Box<dyn PartialReflect>) {
102
self.push_arg(ArgValue::Owned(arg));
103
}
104
105
/// Push an [`ArgValue`] onto the list.
106
///
107
/// If an argument was previously removed from the beginning of the list,
108
/// this method will also re-index the list.
109
pub fn with_arg(mut self, arg: ArgValue<'a>) -> Self {
110
self.push_arg(arg);
111
self
112
}
113
114
/// Push an [`ArgValue::Ref`] onto the list with the given reference.
115
///
116
/// If an argument was previously removed from the beginning of the list,
117
/// this method will also re-index the list.
118
pub fn with_ref(self, arg: &'a dyn PartialReflect) -> Self {
119
self.with_arg(ArgValue::Ref(arg))
120
}
121
122
/// Push an [`ArgValue::Mut`] onto the list with the given mutable reference.
123
///
124
/// If an argument was previously removed from the beginning of the list,
125
/// this method will also re-index the list.
126
pub fn with_mut(self, arg: &'a mut dyn PartialReflect) -> Self {
127
self.with_arg(ArgValue::Mut(arg))
128
}
129
130
/// Push an [`ArgValue::Owned`] onto the list with the given owned value.
131
///
132
/// If an argument was previously removed from the beginning of the list,
133
/// this method will also re-index the list.
134
pub fn with_owned(self, arg: impl PartialReflect) -> Self {
135
self.with_arg(ArgValue::Owned(Box::new(arg)))
136
}
137
138
/// Push an [`ArgValue::Owned`] onto the list with the given boxed value.
139
///
140
/// If an argument was previously removed from the beginning of the list,
141
/// this method will also re-index the list.
142
pub fn with_boxed(self, arg: Box<dyn PartialReflect>) -> Self {
143
self.with_arg(ArgValue::Owned(arg))
144
}
145
146
/// Remove the first argument in the list and return it.
147
///
148
/// It's generally preferred to use [`Self::take`] instead of this method
149
/// as it provides a more ergonomic way to immediately downcast the argument.
150
pub fn take_arg(&mut self) -> Result<Arg<'a>, ArgError> {
151
self.needs_reindex = true;
152
self.list.pop_front().ok_or(ArgError::EmptyArgList)
153
}
154
155
/// Remove the first argument in the list and return `Ok(T::This)`.
156
///
157
/// If the list is empty or the [`FromArg::from_arg`] call fails, returns an error.
158
///
159
/// # Example
160
///
161
/// ```
162
/// # use bevy_reflect::func::ArgList;
163
/// let a = 1u32;
164
/// let b = 2u32;
165
/// let mut c = 3u32;
166
/// let mut args = ArgList::new().with_owned(a).with_ref(&b).with_mut(&mut c);
167
///
168
/// let a = args.take::<u32>().unwrap();
169
/// assert_eq!(a, 1);
170
///
171
/// let b = args.take::<&u32>().unwrap();
172
/// assert_eq!(*b, 2);
173
///
174
/// let c = args.take::<&mut u32>().unwrap();
175
/// assert_eq!(*c, 3);
176
/// ```
177
pub fn take<T: FromArg>(&mut self) -> Result<T::This<'a>, ArgError> {
178
self.take_arg()?.take::<T>()
179
}
180
181
/// Remove the first argument in the list and return `Ok(T)` if the argument is [`ArgValue::Owned`].
182
///
183
/// If the list is empty or the argument is not owned, returns an error.
184
///
185
/// It's generally preferred to use [`Self::take`] instead of this method.
186
///
187
/// # Example
188
///
189
/// ```
190
/// # use bevy_reflect::func::ArgList;
191
/// let value = 123u32;
192
/// let mut args = ArgList::new().with_owned(value);
193
/// let value = args.take_owned::<u32>().unwrap();
194
/// assert_eq!(value, 123);
195
/// ```
196
pub fn take_owned<T: Reflect + TypePath>(&mut self) -> Result<T, ArgError> {
197
self.take_arg()?.take_owned()
198
}
199
200
/// Remove the first argument in the list and return `Ok(&T)` if the argument is [`ArgValue::Ref`].
201
///
202
/// If the list is empty or the argument is not a reference, returns an error.
203
///
204
/// It's generally preferred to use [`Self::take`] instead of this method.
205
///
206
/// # Example
207
///
208
/// ```
209
/// # use bevy_reflect::func::ArgList;
210
/// let value = 123u32;
211
/// let mut args = ArgList::new().with_ref(&value);
212
/// let value = args.take_ref::<u32>().unwrap();
213
/// assert_eq!(*value, 123);
214
/// ```
215
pub fn take_ref<T: Reflect + TypePath>(&mut self) -> Result<&'a T, ArgError> {
216
self.take_arg()?.take_ref()
217
}
218
219
/// Remove the first argument in the list and return `Ok(&mut T)` if the argument is [`ArgValue::Mut`].
220
///
221
/// If the list is empty or the argument is not a mutable reference, returns an error.
222
///
223
/// It's generally preferred to use [`Self::take`] instead of this method.
224
///
225
/// # Example
226
///
227
/// ```
228
/// # use bevy_reflect::func::ArgList;
229
/// let mut value = 123u32;
230
/// let mut args = ArgList::new().with_mut(&mut value);
231
/// let value = args.take_mut::<u32>().unwrap();
232
/// assert_eq!(*value, 123);
233
/// ```
234
pub fn take_mut<T: Reflect + TypePath>(&mut self) -> Result<&'a mut T, ArgError> {
235
self.take_arg()?.take_mut()
236
}
237
238
/// Remove the last argument in the list and return it.
239
///
240
/// It's generally preferred to use [`Self::pop`] instead of this method
241
/// as it provides a more ergonomic way to immediately downcast the argument.
242
pub fn pop_arg(&mut self) -> Result<Arg<'a>, ArgError> {
243
self.list.pop_back().ok_or(ArgError::EmptyArgList)
244
}
245
246
/// Remove the last argument in the list and return `Ok(T::This)`.
247
///
248
/// If the list is empty or the [`FromArg::from_arg`] call fails, returns an error.
249
///
250
/// # Example
251
///
252
/// ```
253
/// # use bevy_reflect::func::ArgList;
254
/// let a = 1u32;
255
/// let b = 2u32;
256
/// let mut c = 3u32;
257
/// let mut args = ArgList::new().with_owned(a).with_ref(&b).with_mut(&mut c);
258
///
259
/// let c = args.pop::<&mut u32>().unwrap();
260
/// assert_eq!(*c, 3);
261
///
262
/// let b = args.pop::<&u32>().unwrap();
263
/// assert_eq!(*b, 2);
264
///
265
/// let a = args.pop::<u32>().unwrap();
266
/// assert_eq!(a, 1);
267
/// ```
268
pub fn pop<T: FromArg>(&mut self) -> Result<T::This<'a>, ArgError> {
269
self.pop_arg()?.take::<T>()
270
}
271
272
/// Remove the last argument in the list and return `Ok(T)` if the argument is [`ArgValue::Owned`].
273
///
274
/// If the list is empty or the argument is not owned, returns an error.
275
///
276
/// It's generally preferred to use [`Self::pop`] instead of this method.
277
///
278
/// # Example
279
///
280
/// ```
281
/// # use bevy_reflect::func::ArgList;
282
/// let value = 123u32;
283
/// let mut args = ArgList::new().with_owned(value);
284
/// let value = args.pop_owned::<u32>().unwrap();
285
/// assert_eq!(value, 123);
286
/// ```
287
pub fn pop_owned<T: Reflect + TypePath>(&mut self) -> Result<T, ArgError> {
288
self.pop_arg()?.take_owned()
289
}
290
291
/// Remove the last argument in the list and return `Ok(&T)` if the argument is [`ArgValue::Ref`].
292
///
293
/// If the list is empty or the argument is not a reference, returns an error.
294
///
295
/// It's generally preferred to use [`Self::pop`] instead of this method.
296
///
297
/// # Example
298
///
299
/// ```
300
/// # use bevy_reflect::func::ArgList;
301
/// let value = 123u32;
302
/// let mut args = ArgList::new().with_ref(&value);
303
/// let value = args.pop_ref::<u32>().unwrap();
304
/// assert_eq!(*value, 123);
305
/// ```
306
pub fn pop_ref<T: Reflect + TypePath>(&mut self) -> Result<&'a T, ArgError> {
307
self.pop_arg()?.take_ref()
308
}
309
310
/// Remove the last argument in the list and return `Ok(&mut T)` if the argument is [`ArgValue::Mut`].
311
///
312
/// If the list is empty or the argument is not a mutable reference, returns an error.
313
///
314
/// It's generally preferred to use [`Self::pop`] instead of this method.
315
///
316
/// # Example
317
///
318
/// ```
319
/// # use bevy_reflect::func::ArgList;
320
/// let mut value = 123u32;
321
/// let mut args = ArgList::new().with_mut(&mut value);
322
/// let value = args.pop_mut::<u32>().unwrap();
323
/// assert_eq!(*value, 123);
324
/// ```
325
pub fn pop_mut<T: Reflect + TypePath>(&mut self) -> Result<&'a mut T, ArgError> {
326
self.pop_arg()?.take_mut()
327
}
328
329
/// Returns an iterator over the arguments in the list.
330
pub fn iter(&self) -> Iter<'_, Arg<'a>> {
331
self.list.iter()
332
}
333
334
/// Returns the number of arguments in the list.
335
pub fn len(&self) -> usize {
336
self.list.len()
337
}
338
339
/// Returns `true` if the list of arguments is empty.
340
pub fn is_empty(&self) -> bool {
341
self.list.is_empty()
342
}
343
}
344
345
#[cfg(test)]
346
mod tests {
347
use super::*;
348
use alloc::string::String;
349
350
#[test]
351
fn should_push_arguments_in_order() {
352
let args = ArgList::new()
353
.with_owned(123)
354
.with_owned(456)
355
.with_owned(789);
356
357
assert_eq!(args.len(), 3);
358
assert_eq!(args.list[0].index(), 0);
359
assert_eq!(args.list[1].index(), 1);
360
assert_eq!(args.list[2].index(), 2);
361
}
362
363
#[test]
364
fn should_push_arg_with_correct_ownership() {
365
let a = String::from("a");
366
let b = String::from("b");
367
let mut c = String::from("c");
368
let d = String::from("d");
369
let e = String::from("e");
370
let f = String::from("f");
371
let mut g = String::from("g");
372
373
let args = ArgList::new()
374
.with_arg(ArgValue::Owned(Box::new(a)))
375
.with_arg(ArgValue::Ref(&b))
376
.with_arg(ArgValue::Mut(&mut c))
377
.with_owned(d)
378
.with_boxed(Box::new(e))
379
.with_ref(&f)
380
.with_mut(&mut g);
381
382
assert!(matches!(args.list[0].value(), &ArgValue::Owned(_)));
383
assert!(matches!(args.list[1].value(), &ArgValue::Ref(_)));
384
assert!(matches!(args.list[2].value(), &ArgValue::Mut(_)));
385
assert!(matches!(args.list[3].value(), &ArgValue::Owned(_)));
386
assert!(matches!(args.list[4].value(), &ArgValue::Owned(_)));
387
assert!(matches!(args.list[5].value(), &ArgValue::Ref(_)));
388
assert!(matches!(args.list[6].value(), &ArgValue::Mut(_)));
389
}
390
391
#[test]
392
fn should_take_args_in_order() {
393
let a = String::from("a");
394
let b = 123_i32;
395
let c = 456_usize;
396
let mut d = 5.78_f32;
397
398
let mut args = ArgList::new()
399
.with_owned(a)
400
.with_ref(&b)
401
.with_ref(&c)
402
.with_mut(&mut d);
403
404
assert_eq!(args.len(), 4);
405
assert_eq!(args.take_owned::<String>().unwrap(), String::from("a"));
406
assert_eq!(args.take::<&i32>().unwrap(), &123);
407
assert_eq!(args.take_ref::<usize>().unwrap(), &456);
408
assert_eq!(args.take_mut::<f32>().unwrap(), &mut 5.78);
409
assert_eq!(args.len(), 0);
410
}
411
412
#[test]
413
fn should_pop_args_in_reverse_order() {
414
let a = String::from("a");
415
let b = 123_i32;
416
let c = 456_usize;
417
let mut d = 5.78_f32;
418
419
let mut args = ArgList::new()
420
.with_owned(a)
421
.with_ref(&b)
422
.with_ref(&c)
423
.with_mut(&mut d);
424
425
assert_eq!(args.len(), 4);
426
assert_eq!(args.pop_mut::<f32>().unwrap(), &mut 5.78);
427
assert_eq!(args.pop_ref::<usize>().unwrap(), &456);
428
assert_eq!(args.pop::<&i32>().unwrap(), &123);
429
assert_eq!(args.pop_owned::<String>().unwrap(), String::from("a"));
430
assert_eq!(args.len(), 0);
431
}
432
433
#[test]
434
fn should_reindex_on_push_after_take() {
435
let mut args = ArgList::new()
436
.with_owned(123)
437
.with_owned(456)
438
.with_owned(789);
439
440
assert!(!args.needs_reindex);
441
442
args.take_arg().unwrap();
443
assert!(args.needs_reindex);
444
assert!(args.list[0].value().reflect_partial_eq(&456).unwrap());
445
assert_eq!(args.list[0].index(), 1);
446
assert!(args.list[1].value().reflect_partial_eq(&789).unwrap());
447
assert_eq!(args.list[1].index(), 2);
448
449
let args = args.with_owned(123);
450
assert!(!args.needs_reindex);
451
assert!(args.list[0].value().reflect_partial_eq(&456).unwrap());
452
assert_eq!(args.list[0].index(), 0);
453
assert!(args.list[1].value().reflect_partial_eq(&789).unwrap());
454
assert_eq!(args.list[1].index(), 1);
455
assert!(args.list[2].value().reflect_partial_eq(&123).unwrap());
456
assert_eq!(args.list[2].index(), 2);
457
}
458
}
459
460