1use crate::type_info::impl_type_methods;
2use crate::{Reflect, Type, TypePath};
3use alloc::{borrow::Cow, boxed::Box};
4use bevy_platform::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 let arc = Arc::new(default);
185
186 #[cfg(not(target_has_atomic = "ptr"))]
187 #[expect(
188 unsafe_code,
189 reason = "unsized coercion is an unstable feature for non-std types"
190 )]
191 let arc = unsafe { Arc::from_raw(Arc::into_raw(arc) as *const dyn Reflect) };
195
196 self.default = Some(arc);
197 self
198 }
199
200 pub fn name(&self) -> &Cow<'static, str> {
202 &self.name
203 }
204
205 pub fn default(&self) -> Option<&dyn Reflect> {
224 self.default.as_deref()
225 }
226
227 impl_type_methods!(ty);
228}
229
230macro_rules! impl_generic_info_methods {
231 ($field:ident) => {
233 $crate::generics::impl_generic_info_methods!(self => &self.$field);
234
235 pub fn with_generics(mut self, generics: crate::generics::Generics) -> Self {
237 self.$field = generics;
238 self
239 }
240 };
241 ($self:ident => $expr:expr) => {
243 pub fn generics(&$self) -> &crate::generics::Generics {
245 $expr
246 }
247 };
248}
249
250pub(crate) use impl_generic_info_methods;
251
252#[cfg(test)]
253mod tests {
254 use super::*;
255 use crate::{Reflect, Typed};
256 use alloc::string::String;
257 use core::fmt::Debug;
258
259 #[test]
260 fn should_maintain_order() {
261 #[derive(Reflect)]
262 struct Test<T, U: Debug, const N: usize>([(T, U); N]);
263
264 let generics = <Test<f32, String, 10> as Typed>::type_info()
265 .as_tuple_struct()
266 .unwrap()
267 .generics();
268
269 assert_eq!(generics.len(), 3);
270
271 let mut iter = generics.iter();
272
273 let t = iter.next().unwrap();
274 assert_eq!(t.name(), "T");
275 assert!(t.ty().is::<f32>());
276 assert!(!t.is_const());
277
278 let u = iter.next().unwrap();
279 assert_eq!(u.name(), "U");
280 assert!(u.ty().is::<String>());
281 assert!(!u.is_const());
282
283 let n = iter.next().unwrap();
284 assert_eq!(n.name(), "N");
285 assert!(n.ty().is::<usize>());
286 assert!(n.is_const());
287
288 assert!(iter.next().is_none());
289 }
290
291 #[test]
292 fn should_get_by_name() {
293 #[derive(Reflect)]
294 enum Test<T, U: Debug, const N: usize> {
295 Array([(T, U); N]),
296 }
297
298 let generics = <Test<f32, String, 10> as Typed>::type_info()
299 .as_enum()
300 .unwrap()
301 .generics();
302
303 let t = generics.get_named("T").unwrap();
304 assert_eq!(t.name(), "T");
305 assert!(t.ty().is::<f32>());
306 assert!(!t.is_const());
307
308 let u = generics.get_named("U").unwrap();
309 assert_eq!(u.name(), "U");
310 assert!(u.ty().is::<String>());
311 assert!(!u.is_const());
312
313 let n = generics.get_named("N").unwrap();
314 assert_eq!(n.name(), "N");
315 assert!(n.ty().is::<usize>());
316 assert!(n.is_const());
317 }
318
319 #[test]
320 fn should_store_defaults() {
321 #[derive(Reflect)]
322 struct Test<T, U: Debug = String, const N: usize = 10>([(T, U); N]);
323
324 let generics = <Test<f32> as Typed>::type_info()
325 .as_tuple_struct()
326 .unwrap()
327 .generics();
328
329 let GenericInfo::Type(u) = generics.get_named("U").unwrap() else {
330 panic!("expected a type parameter");
331 };
332 assert_eq!(u.default().unwrap(), &Type::of::<String>());
333
334 let GenericInfo::Const(n) = generics.get_named("N").unwrap() else {
335 panic!("expected a const parameter");
336 };
337 assert_eq!(n.default().unwrap().downcast_ref::<usize>().unwrap(), &10);
338 }
339}