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#[derive(Clone, Default, Debug)]
26pub struct Generics(Box<[GenericInfo]>);
27
28impl Generics {
29 pub fn new() -> Self {
31 Self(Box::new([]))
32 }
33
34 pub fn get_named(&self, name: &str) -> Option<&GenericInfo> {
38 self.0.iter().find(|info| info.name() == name)
41 }
42
43 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#[derive(Clone, Debug, From)]
68pub enum GenericInfo {
69 Type(TypeParamInfo),
73 Const(ConstParamInfo),
77}
78
79impl GenericInfo {
80 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 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#[derive(Clone, Debug)]
108pub struct TypeParamInfo {
109 name: Cow<'static, str>,
110 ty: Type,
111 default: Option<Type>,
112}
113
114impl TypeParamInfo {
115 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 pub fn with_default<T: TypePath + ?Sized>(mut self) -> Self {
126 self.default = Some(Type::of::<T>());
127 self
128 }
129
130 pub fn name(&self) -> &Cow<'static, str> {
132 &self.name
133 }
134
135 pub fn default(&self) -> Option<&Type> {
154 self.default.as_ref()
155 }
156
157 impl_type_methods!(ty);
158}
159
160#[derive(Clone, Debug)]
164pub struct ConstParamInfo {
165 name: Cow<'static, str>,
166 ty: Type,
167 default: Option<Arc<dyn Reflect>>,
170}
171
172impl ConstParamInfo {
173 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 pub fn with_default<T: Reflect + 'static>(mut self, default: T) -> Self {
184 self.default = Some(Arc::new(default));
185 self
186 }
187
188 pub fn name(&self) -> &Cow<'static, str> {
190 &self.name
191 }
192
193 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 ($field:ident) => {
221 $crate::generics::impl_generic_info_methods!(self => &self.$field);
222
223 pub fn with_generics(mut self, generics: crate::generics::Generics) -> Self {
225 self.$field = generics;
226 self
227 }
228 };
229 ($self:ident => $expr:expr) => {
231 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}