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}