bevy_reflect/
generics.rs

1use crate::type_info::impl_type_methods;
2use crate::{Reflect, Type, TypePath};
3use alloc::borrow::Cow;
4use alloc::sync::Arc;
5use core::ops::Deref;
6use derive_more::derive::From;
7
8/// The generic parameters of a type.
9///
10/// This is automatically generated via the [`Reflect` derive macro]
11/// and stored on the [`TypeInfo`] returned by [`Typed::type_info`]
12/// for types that have generics.
13///
14/// It supports both type parameters and const parameters
15/// so long as they implement [`TypePath`].
16///
17/// If the type has no generics, this will be empty.
18///
19/// If the type is marked with `#[reflect(type_path = false)]`,
20/// the generics will be empty even if the type has generics.
21///
22/// [`Reflect` derive macro]: bevy_reflect_derive::Reflect
23/// [`TypeInfo`]: crate::type_info::TypeInfo
24/// [`Typed::type_info`]: crate::Typed::type_info
25#[derive(Clone, Default, Debug)]
26pub struct Generics(Box<[GenericInfo]>);
27
28impl Generics {
29    /// Creates an empty set of generics.
30    pub fn new() -> Self {
31        Self(Box::new([]))
32    }
33
34    /// Finds the generic parameter with the given name.
35    ///
36    /// Returns `None` if no such parameter exists.
37    pub fn get_named(&self, name: &str) -> Option<&GenericInfo> {
38        // For small sets of generics (the most common case),
39        // a linear search is often faster using a `HashMap`.
40        self.0.iter().find(|info| info.name() == name)
41    }
42
43    /// Adds the given generic parameter to the set.
44    pub fn with(mut self, info: impl Into<GenericInfo>) -> Self {
45        self.0 = IntoIterator::into_iter(self.0)
46            .chain(core::iter::once(info.into()))
47            .collect();
48        self
49    }
50}
51
52impl<T: Into<GenericInfo>> FromIterator<T> for Generics {
53    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
54        Self(iter.into_iter().map(Into::into).collect())
55    }
56}
57
58impl Deref for Generics {
59    type Target = [GenericInfo];
60
61    fn deref(&self) -> &Self::Target {
62        &self.0
63    }
64}
65
66/// An enum representing a generic parameter.
67#[derive(Clone, Debug, From)]
68pub enum GenericInfo {
69    /// A type parameter.
70    ///
71    /// An example would be `T` in `struct Foo<T, U>`.
72    Type(TypeParamInfo),
73    /// A const parameter.
74    ///
75    /// An example would be `N` in `struct Foo<const N: usize>`.
76    Const(ConstParamInfo),
77}
78
79impl GenericInfo {
80    /// The name of the generic parameter.
81    pub fn name(&self) -> &Cow<'static, str> {
82        match self {
83            Self::Type(info) => info.name(),
84            Self::Const(info) => info.name(),
85        }
86    }
87
88    /// Whether the generic parameter is a const parameter.
89    pub fn is_const(&self) -> bool {
90        match self {
91            Self::Type(_) => false,
92            Self::Const(_) => true,
93        }
94    }
95
96    impl_type_methods!(self => {
97        match self {
98            Self::Type(info) => info.ty(),
99            Self::Const(info) => info.ty(),
100        }
101    });
102}
103
104/// Type information for a generic type parameter.
105///
106/// An example of a type parameter would be `T` in `struct Foo<T>`.
107#[derive(Clone, Debug)]
108pub struct TypeParamInfo {
109    name: Cow<'static, str>,
110    ty: Type,
111    default: Option<Type>,
112}
113
114impl TypeParamInfo {
115    /// Creates a new type parameter with the given name.
116    pub fn new<T: TypePath + ?Sized>(name: impl Into<Cow<'static, str>>) -> Self {
117        Self {
118            name: name.into(),
119            ty: Type::of::<T>(),
120            default: None,
121        }
122    }
123
124    /// Sets the default type for the parameter.
125    pub fn with_default<T: TypePath + ?Sized>(mut self) -> Self {
126        self.default = Some(Type::of::<T>());
127        self
128    }
129
130    /// The name of the type parameter.
131    pub fn name(&self) -> &Cow<'static, str> {
132        &self.name
133    }
134
135    /// The default type for the parameter, if any.
136    ///
137    /// # Example
138    ///
139    /// ```
140    /// # use bevy_reflect::{GenericInfo, Reflect, Typed};
141    /// #[derive(Reflect)]
142    /// struct Foo<T = f32>(T);
143    ///
144    /// let generics = Foo::<String>::type_info().generics();
145    /// let GenericInfo::Type(info) = generics.get_named("T").unwrap() else {
146    ///     panic!("expected a type parameter");
147    /// };
148    ///
149    /// let default = info.default().unwrap();
150    ///
151    /// assert!(default.is::<f32>());
152    /// ```
153    pub fn default(&self) -> Option<&Type> {
154        self.default.as_ref()
155    }
156
157    impl_type_methods!(ty);
158}
159
160/// Type information for a const generic parameter.
161///
162/// An example of a const parameter would be `N` in `struct Foo<const N: usize>`.
163#[derive(Clone, Debug)]
164pub struct ConstParamInfo {
165    name: Cow<'static, str>,
166    ty: Type,
167    // Rust currently only allows certain primitive types in const generic position,
168    // meaning that `Reflect` is guaranteed to be implemented for the default value.
169    default: Option<Arc<dyn Reflect>>,
170}
171
172impl ConstParamInfo {
173    /// Creates a new const parameter with the given name.
174    pub fn new<T: TypePath + ?Sized>(name: impl Into<Cow<'static, str>>) -> Self {
175        Self {
176            name: name.into(),
177            ty: Type::of::<T>(),
178            default: None,
179        }
180    }
181
182    /// Sets the default value for the parameter.
183    pub fn with_default<T: Reflect + 'static>(mut self, default: T) -> Self {
184        self.default = Some(Arc::new(default));
185        self
186    }
187
188    /// The name of the const parameter.
189    pub fn name(&self) -> &Cow<'static, str> {
190        &self.name
191    }
192
193    /// The default value for the parameter, if any.
194    ///
195    /// # Example
196    ///
197    /// ```
198    /// # use bevy_reflect::{GenericInfo, Reflect, Typed};
199    /// #[derive(Reflect)]
200    /// struct Foo<const N: usize = 10>([u8; N]);
201    ///
202    /// let generics = Foo::<5>::type_info().generics();
203    /// let GenericInfo::Const(info) = generics.get_named("N").unwrap() else {
204    ///    panic!("expected a const parameter");
205    /// };
206    ///
207    /// let default = info.default().unwrap();
208    ///
209    /// assert_eq!(default.downcast_ref::<usize>().unwrap(), &10);
210    /// ```
211    pub fn default(&self) -> Option<&dyn Reflect> {
212        self.default.as_deref()
213    }
214
215    impl_type_methods!(ty);
216}
217
218macro_rules! impl_generic_info_methods {
219    // Implements both getter and setter methods for the given field.
220    ($field:ident) => {
221        $crate::generics::impl_generic_info_methods!(self => &self.$field);
222
223        /// Sets the generic parameters for this type.
224        pub fn with_generics(mut self, generics: crate::generics::Generics) -> Self {
225            self.$field = generics;
226            self
227        }
228    };
229    // Implements only a getter method for the given expression.
230    ($self:ident => $expr:expr) => {
231        /// Gets the generic parameters for this type.
232        pub fn generics(&$self) -> &crate::generics::Generics {
233            $expr
234        }
235    };
236}
237
238pub(crate) use impl_generic_info_methods;
239
240#[cfg(test)]
241mod tests {
242    use super::*;
243    use crate as bevy_reflect;
244    use crate::{Reflect, Typed};
245    use core::fmt::Debug;
246
247    #[test]
248    fn should_maintain_order() {
249        #[derive(Reflect)]
250        struct Test<T, U: Debug, const N: usize>([(T, U); N]);
251
252        let generics = <Test<f32, String, 10> as Typed>::type_info()
253            .as_tuple_struct()
254            .unwrap()
255            .generics();
256
257        assert_eq!(generics.len(), 3);
258
259        let mut iter = generics.iter();
260
261        let t = iter.next().unwrap();
262        assert_eq!(t.name(), "T");
263        assert!(t.ty().is::<f32>());
264        assert!(!t.is_const());
265
266        let u = iter.next().unwrap();
267        assert_eq!(u.name(), "U");
268        assert!(u.ty().is::<String>());
269        assert!(!u.is_const());
270
271        let n = iter.next().unwrap();
272        assert_eq!(n.name(), "N");
273        assert!(n.ty().is::<usize>());
274        assert!(n.is_const());
275
276        assert!(iter.next().is_none());
277    }
278
279    #[test]
280    fn should_get_by_name() {
281        #[derive(Reflect)]
282        enum Test<T, U: Debug, const N: usize> {
283            Array([(T, U); N]),
284        }
285
286        let generics = <Test<f32, String, 10> as Typed>::type_info()
287            .as_enum()
288            .unwrap()
289            .generics();
290
291        let t = generics.get_named("T").unwrap();
292        assert_eq!(t.name(), "T");
293        assert!(t.ty().is::<f32>());
294        assert!(!t.is_const());
295
296        let u = generics.get_named("U").unwrap();
297        assert_eq!(u.name(), "U");
298        assert!(u.ty().is::<String>());
299        assert!(!u.is_const());
300
301        let n = generics.get_named("N").unwrap();
302        assert_eq!(n.name(), "N");
303        assert!(n.ty().is::<usize>());
304        assert!(n.is_const());
305    }
306
307    #[test]
308    fn should_store_defaults() {
309        #[derive(Reflect)]
310        struct Test<T, U: Debug = String, const N: usize = 10>([(T, U); N]);
311
312        let generics = <Test<f32> as Typed>::type_info()
313            .as_tuple_struct()
314            .unwrap()
315            .generics();
316
317        let GenericInfo::Type(u) = generics.get_named("U").unwrap() else {
318            panic!("expected a type parameter");
319        };
320        assert_eq!(u.default().unwrap(), &Type::of::<String>());
321
322        let GenericInfo::Const(n) = generics.get_named("N").unwrap() else {
323            panic!("expected a const parameter");
324        };
325        assert_eq!(n.default().unwrap().downcast_ref::<usize>().unwrap(), &10);
326    }
327}