bevy_reflect/func/args/arg.rs
1use crate::{
2 func::args::{ArgError, FromArg, Ownership},
3 PartialReflect, Reflect, TypePath,
4};
5use alloc::{boxed::Box, string::ToString};
6use core::ops::Deref;
7
8/// Represents an argument that can be passed to a [`DynamicFunction`] or [`DynamicFunctionMut`].
9///
10/// [`DynamicFunction`]: crate::func::DynamicFunction
11/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
12#[derive(Debug)]
13pub struct Arg<'a> {
14 index: usize,
15 value: ArgValue<'a>,
16}
17
18impl<'a> Arg<'a> {
19 /// Create a new [`Arg`] with the given index and value.
20 pub fn new(index: usize, value: ArgValue<'a>) -> Self {
21 Self { index, value }
22 }
23
24 /// The index of the argument.
25 pub fn index(&self) -> usize {
26 self.index
27 }
28
29 /// Set the index of the argument.
30 pub(crate) fn set_index(&mut self, index: usize) {
31 self.index = index;
32 }
33
34 /// The value of the argument.
35 pub fn value(&self) -> &ArgValue<'a> {
36 &self.value
37 }
38
39 /// Take the value of the argument.
40 pub fn take_value(self) -> ArgValue<'a> {
41 self.value
42 }
43
44 /// Take the value of the argument and attempt to convert it to a concrete value, `T`.
45 ///
46 /// This is a convenience method for calling [`FromArg::from_arg`] on the argument.
47 ///
48 /// # Example
49 ///
50 /// ```
51 /// # use bevy_reflect::func::ArgList;
52 /// let a = 1u32;
53 /// let b = 2u32;
54 /// let mut c = 3u32;
55 /// let mut args = ArgList::new().with_owned(a).with_ref(&b).with_mut(&mut c);
56 ///
57 /// let a = args.take::<u32>().unwrap();
58 /// assert_eq!(a, 1);
59 ///
60 /// let b = args.take::<&u32>().unwrap();
61 /// assert_eq!(*b, 2);
62 ///
63 /// let c = args.take::<&mut u32>().unwrap();
64 /// assert_eq!(*c, 3);
65 /// ```
66 pub fn take<T: FromArg>(self) -> Result<T::This<'a>, ArgError> {
67 T::from_arg(self)
68 }
69
70 /// Returns `Ok(T)` if the argument is [`ArgValue::Owned`].
71 ///
72 /// If the argument is not owned, returns an error.
73 ///
74 /// It's generally preferred to use [`Self::take`] instead of this method.
75 ///
76 /// # Example
77 ///
78 /// ```
79 /// # use bevy_reflect::func::ArgList;
80 /// let value = 123u32;
81 /// let mut args = ArgList::new().with_owned(value);
82 /// let value = args.take_owned::<u32>().unwrap();
83 /// assert_eq!(value, 123);
84 /// ```
85 pub fn take_owned<T: Reflect + TypePath>(self) -> Result<T, ArgError> {
86 match self.value {
87 ArgValue::Owned(arg) => arg.try_take().map_err(|arg| ArgError::UnexpectedType {
88 index: self.index,
89 expected: alloc::borrow::Cow::Borrowed(T::type_path()),
90 received: alloc::borrow::Cow::Owned(arg.reflect_type_path().to_string()),
91 }),
92 ArgValue::Ref(_) => Err(ArgError::InvalidOwnership {
93 index: self.index,
94 expected: Ownership::Owned,
95 received: Ownership::Ref,
96 }),
97 ArgValue::Mut(_) => Err(ArgError::InvalidOwnership {
98 index: self.index,
99 expected: Ownership::Owned,
100 received: Ownership::Mut,
101 }),
102 }
103 }
104
105 /// Returns `Ok(&T)` if the argument is [`ArgValue::Ref`].
106 ///
107 /// If the argument is not a reference, returns an error.
108 ///
109 /// It's generally preferred to use [`Self::take`] instead of this method.
110 ///
111 /// # Example
112 ///
113 /// ```
114 /// # use bevy_reflect::func::ArgList;
115 /// let value = 123u32;
116 /// let mut args = ArgList::new().with_ref(&value);
117 /// let value = args.take_ref::<u32>().unwrap();
118 /// assert_eq!(*value, 123);
119 /// ```
120 pub fn take_ref<T: Reflect + TypePath>(self) -> Result<&'a T, ArgError> {
121 match self.value {
122 ArgValue::Owned(_) => Err(ArgError::InvalidOwnership {
123 index: self.index,
124 expected: Ownership::Ref,
125 received: Ownership::Owned,
126 }),
127 ArgValue::Ref(arg) => {
128 Ok(arg
129 .try_downcast_ref()
130 .ok_or_else(|| ArgError::UnexpectedType {
131 index: self.index,
132 expected: alloc::borrow::Cow::Borrowed(T::type_path()),
133 received: alloc::borrow::Cow::Owned(arg.reflect_type_path().to_string()),
134 })?)
135 }
136 ArgValue::Mut(_) => Err(ArgError::InvalidOwnership {
137 index: self.index,
138 expected: Ownership::Ref,
139 received: Ownership::Mut,
140 }),
141 }
142 }
143
144 /// Returns `Ok(&mut T)` if the argument is [`ArgValue::Mut`].
145 ///
146 /// If the argument is not a mutable reference, returns an error.
147 ///
148 /// It's generally preferred to use [`Self::take`] instead of this method.
149 ///
150 /// # Example
151 ///
152 /// ```
153 /// # use bevy_reflect::func::ArgList;
154 /// let mut value = 123u32;
155 /// let mut args = ArgList::new().with_mut(&mut value);
156 /// let value = args.take_mut::<u32>().unwrap();
157 /// assert_eq!(*value, 123);
158 /// ```
159 pub fn take_mut<T: Reflect + TypePath>(self) -> Result<&'a mut T, ArgError> {
160 match self.value {
161 ArgValue::Owned(_) => Err(ArgError::InvalidOwnership {
162 index: self.index,
163 expected: Ownership::Mut,
164 received: Ownership::Owned,
165 }),
166 ArgValue::Ref(_) => Err(ArgError::InvalidOwnership {
167 index: self.index,
168 expected: Ownership::Mut,
169 received: Ownership::Ref,
170 }),
171 ArgValue::Mut(arg) => {
172 let received = alloc::borrow::Cow::Owned(arg.reflect_type_path().to_string());
173 Ok(arg
174 .try_downcast_mut()
175 .ok_or_else(|| ArgError::UnexpectedType {
176 index: self.index,
177 expected: alloc::borrow::Cow::Borrowed(T::type_path()),
178 received,
179 })?)
180 }
181 }
182 }
183
184 /// Returns `true` if the argument is of type `T`.
185 pub fn is<T: TypePath>(&self) -> bool {
186 self.value
187 .try_as_reflect()
188 .map(<dyn Reflect>::is::<T>)
189 .unwrap_or_default()
190 }
191}
192
193/// Represents an argument that can be passed to a [`DynamicFunction`] or [`DynamicFunctionMut`].
194///
195/// [`DynamicFunction`]: crate::func::DynamicFunction
196/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
197#[derive(Debug)]
198pub enum ArgValue<'a> {
199 /// An owned argument.
200 Owned(Box<dyn PartialReflect>),
201 /// An immutable reference argument.
202 Ref(&'a dyn PartialReflect),
203 /// A mutable reference argument.
204 Mut(&'a mut dyn PartialReflect),
205}
206
207impl<'a> Deref for ArgValue<'a> {
208 type Target = dyn PartialReflect;
209
210 fn deref(&self) -> &Self::Target {
211 match self {
212 ArgValue::Owned(arg) => arg.as_ref(),
213 ArgValue::Ref(arg) => *arg,
214 ArgValue::Mut(arg) => *arg,
215 }
216 }
217}