1use alloc::boxed::Box;
5use core::{any::TypeId, marker::PhantomData};
6
7use bevy_utils::TypeIdMap;
8
9use crate::{Reflect, TypePath};
10
11#[derive(Default)]
36pub struct ReflectConvert {
37 conversions: TypeIdMap<Box<dyn Converter>>,
40}
41
42trait Converter: Send + Sync {
44 fn convert(&self, input: Box<dyn Reflect>) -> Result<Box<dyn Reflect>, Box<dyn Reflect>>;
49
50 fn clone_converter(&self) -> Box<dyn Converter>;
52}
53
54struct TypedConverter<T, U, F>
56where
57 T: Reflect + TypePath,
58 U: Reflect + TypePath,
59 F: Fn(T) -> Result<U, T> + Clone + Send + Sync + 'static,
60{
61 function: F,
62 phantom: PhantomData<(T, U)>,
63}
64
65impl ReflectConvert {
66 pub fn try_convert_from(
73 &self,
74 input: Box<dyn Reflect>,
75 ) -> Result<Box<dyn Reflect>, Box<dyn Reflect>> {
76 let type_id = (*input.as_any()).type_id();
77 match self.conversions.get(&type_id) {
78 Some(converter) => converter.convert(input),
79 None => Err(input),
80 }
81 }
82
83 pub fn register_type_conversion<T, U, F>(&mut self, function: F)
89 where
90 T: Reflect + TypePath,
91 U: Reflect + TypePath,
92 F: Fn(T) -> Result<U, T> + Clone + Send + Sync + 'static,
93 {
94 self.conversions.insert(
95 TypeId::of::<T>(),
96 Box::new(TypedConverter {
97 function,
98 phantom: PhantomData,
99 }),
100 );
101 }
102}
103
104impl Clone for ReflectConvert {
105 fn clone(&self) -> Self {
106 ReflectConvert {
107 conversions: self
108 .conversions
109 .iter()
110 .map(|(type_id, converter)| (*type_id, converter.clone_converter()))
111 .collect(),
112 }
113 }
114}
115
116impl<T, U, F> Clone for TypedConverter<T, U, F>
117where
118 T: Reflect + TypePath,
119 U: Reflect + TypePath,
120 F: Fn(T) -> Result<U, T> + Clone + Send + Sync + 'static,
121{
122 fn clone(&self) -> Self {
123 TypedConverter {
124 function: self.function.clone(),
125 phantom: PhantomData,
126 }
127 }
128}
129
130impl<T, U, F> Converter for TypedConverter<T, U, F>
131where
132 T: Reflect + TypePath,
133 U: Reflect + TypePath,
134 F: Fn(T) -> Result<U, T> + Clone + Send + Sync + 'static,
135{
136 fn convert(&self, input: Box<dyn Reflect>) -> Result<Box<dyn Reflect>, Box<dyn Reflect>> {
137 let mut input = input.downcast::<T>()?;
138 match (self.function)(*input) {
139 Ok(value) => Ok(Box::new(value)),
140 Err(value) => {
141 *input = value;
142 Err(input)
143 }
144 }
145 }
146
147 fn clone_converter(&self) -> Box<dyn Converter> {
148 Box::new(self.clone())
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use alloc::{
155 borrow::ToOwned as _,
156 boxed::Box,
157 string::{String, ToString},
158 };
159 use core::any::TypeId;
160
161 use crate::{convert::ReflectConvert, type_registry::GetTypeRegistration, TypeRegistry};
162
163 #[test]
166 fn convert_from_i32_to_string() {
167 let mut registry = TypeRegistry::default();
169 registry.add_registration(i32::get_type_registration());
170 registry.add_registration(String::get_type_registration());
171 registry.register_type_conversion(|x: i32| Ok(x.to_string()));
172
173 let reflect_convert = registry
174 .get_type_data::<ReflectConvert>(TypeId::of::<String>())
175 .unwrap();
176
177 let converted = reflect_convert
179 .try_convert_from(Box::new(12345i32))
180 .unwrap()
181 .downcast::<String>()
182 .unwrap();
183 assert_eq!(&**converted, "12345");
184 }
185
186 #[test]
192 fn convert_from_string_to_i32() {
193 let mut registry = TypeRegistry::default();
195 registry.add_registration(i32::get_type_registration());
196 registry.add_registration(String::get_type_registration());
197 registry.register_type_conversion(|x: String| match x.parse::<i32>() {
198 Ok(value) => Ok(value),
199 Err(_) => Err(x),
200 });
201
202 let reflect_convert = registry
203 .get_type_data::<ReflectConvert>(TypeId::of::<i32>())
204 .unwrap();
205
206 let converted = reflect_convert
208 .try_convert_from(Box::new("12345".to_owned()))
209 .unwrap()
210 .downcast::<i32>()
211 .unwrap();
212 assert_eq!(*converted, 12345);
213
214 let error = reflect_convert
216 .try_convert_from(Box::new("qqqqq".to_owned()))
217 .unwrap_err()
218 .downcast::<String>()
219 .unwrap();
220 assert_eq!(&**error, "qqqqq");
221 }
222
223 #[test]
226 fn convert_from_f32_and_u32_to_i32() {
227 let mut registry = TypeRegistry::default();
228 registry.add_registration(i32::get_type_registration());
229 registry.add_registration(f32::get_type_registration());
230 registry.add_registration(u32::get_type_registration());
231 registry.register_type_conversion::<u32, i32, _>(|n: u32| n.try_into().map_err(|_| n));
232 registry.register_type_conversion::<f32, i32, _>(|n: f32| Ok(n as i32));
233
234 let reflect_convert = registry
235 .get_type_data::<ReflectConvert>(TypeId::of::<i32>())
236 .unwrap();
237
238 let a = reflect_convert
240 .try_convert_from(Box::new(99u32))
241 .unwrap()
242 .downcast::<i32>()
243 .unwrap();
244 assert_eq!(*a, 99i32);
245 let b = reflect_convert
246 .try_convert_from(Box::new(99.0f32))
247 .unwrap()
248 .downcast::<i32>()
249 .unwrap();
250 assert_eq!(*b, 99i32);
251 }
252
253 #[test]
256 fn no_such_conversion() {
257 let mut registry = TypeRegistry::default();
258 registry.add_registration(i32::get_type_registration());
259 registry.add_registration(String::get_type_registration());
260 registry
261 .get_mut(TypeId::of::<i32>())
262 .unwrap()
263 .insert(ReflectConvert::default());
264
265 let reflect_convert = registry
266 .get_type_data::<ReflectConvert>(TypeId::of::<i32>())
267 .unwrap();
268
269 let error = reflect_convert
271 .try_convert_from(Box::new("12345".to_owned()))
272 .unwrap_err()
273 .downcast::<String>()
274 .unwrap();
275 assert_eq!(&**error, "12345");
276 }
277}