1use alloc::boxed::Box;
2use thiserror::Error;
3
4#[cfg(feature = "functions")]
5use crate::func::Function;
6use crate::{Array, Enum, List, Map, PartialReflect, Set, Struct, Tuple, TupleStruct};
7
8#[derive(Debug, PartialEq, Eq, Clone, Copy)]
17pub enum ReflectKind {
18 Struct,
22 TupleStruct,
26 Tuple,
30 List,
34 Array,
38 Map,
42 Set,
46 Enum,
50 #[cfg(feature = "functions")]
54 Function,
55 Opaque,
70}
71
72impl core::fmt::Display for ReflectKind {
73 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
74 match self {
75 ReflectKind::Struct => f.pad("struct"),
76 ReflectKind::TupleStruct => f.pad("tuple struct"),
77 ReflectKind::Tuple => f.pad("tuple"),
78 ReflectKind::List => f.pad("list"),
79 ReflectKind::Array => f.pad("array"),
80 ReflectKind::Map => f.pad("map"),
81 ReflectKind::Set => f.pad("set"),
82 ReflectKind::Enum => f.pad("enum"),
83 #[cfg(feature = "functions")]
84 ReflectKind::Function => f.pad("function"),
85 ReflectKind::Opaque => f.pad("opaque"),
86 }
87 }
88}
89
90macro_rules! impl_reflect_kind_conversions {
91 ($name:ident$(<$lifetime:lifetime>)?) => {
92 impl $name$(<$lifetime>)? {
93 pub fn kind(&self) -> ReflectKind {
95 match self {
96 Self::Struct(_) => ReflectKind::Struct,
97 Self::TupleStruct(_) => ReflectKind::TupleStruct,
98 Self::Tuple(_) => ReflectKind::Tuple,
99 Self::List(_) => ReflectKind::List,
100 Self::Array(_) => ReflectKind::Array,
101 Self::Map(_) => ReflectKind::Map,
102 Self::Set(_) => ReflectKind::Set,
103 Self::Enum(_) => ReflectKind::Enum,
104 #[cfg(feature = "functions")]
105 Self::Function(_) => ReflectKind::Function,
106 Self::Opaque(_) => ReflectKind::Opaque,
107 }
108 }
109 }
110
111 impl From<$name$(<$lifetime>)?> for ReflectKind {
112 fn from(value: $name) -> Self {
113 match value {
114 $name::Struct(_) => Self::Struct,
115 $name::TupleStruct(_) => Self::TupleStruct,
116 $name::Tuple(_) => Self::Tuple,
117 $name::List(_) => Self::List,
118 $name::Array(_) => Self::Array,
119 $name::Map(_) => Self::Map,
120 $name::Set(_) => Self::Set,
121 $name::Enum(_) => Self::Enum,
122 #[cfg(feature = "functions")]
123 $name::Function(_) => Self::Function,
124 $name::Opaque(_) => Self::Opaque,
125 }
126 }
127 }
128 };
129}
130
131#[derive(Debug, Error)]
135#[error("kind mismatch: expected {expected:?}, received {received:?}")]
136pub struct ReflectKindMismatchError {
137 pub expected: ReflectKind,
138 pub received: ReflectKind,
139}
140
141macro_rules! impl_cast_method {
142 ($name:ident : Opaque => $retval:ty) => {
143 #[doc = "Attempts a cast to a [`PartialReflect`] trait object."]
144 #[doc = "\n\nReturns an error if `self` is not the [`Self::Opaque`] variant."]
145 pub fn $name(self) -> Result<$retval, ReflectKindMismatchError> {
146 match self {
147 Self::Opaque(value) => Ok(value),
148 _ => Err(ReflectKindMismatchError {
149 expected: ReflectKind::Opaque,
150 received: self.kind(),
151 }),
152 }
153 }
154 };
155 ($name:ident : $kind:ident => $retval:ty) => {
156 #[doc = concat!("Attempts a cast to a [`", stringify!($kind), "`] trait object.")]
157 #[doc = concat!("\n\nReturns an error if `self` is not the [`Self::", stringify!($kind), "`] variant.")]
158 pub fn $name(self) -> Result<$retval, ReflectKindMismatchError> {
159 match self {
160 Self::$kind(value) => Ok(value),
161 _ => Err(ReflectKindMismatchError {
162 expected: ReflectKind::$kind,
163 received: self.kind(),
164 }),
165 }
166 }
167 };
168}
169
170pub enum ReflectRef<'a> {
179 Struct(&'a dyn Struct),
180 TupleStruct(&'a dyn TupleStruct),
181 Tuple(&'a dyn Tuple),
182 List(&'a dyn List),
183 Array(&'a dyn Array),
184 Map(&'a dyn Map),
185 Set(&'a dyn Set),
186 Enum(&'a dyn Enum),
187 #[cfg(feature = "functions")]
188 Function(&'a dyn Function),
189 Opaque(&'a dyn PartialReflect),
190}
191impl_reflect_kind_conversions!(ReflectRef<'_>);
192
193impl<'a> ReflectRef<'a> {
194 impl_cast_method!(as_struct: Struct => &'a dyn Struct);
195 impl_cast_method!(as_tuple_struct: TupleStruct => &'a dyn TupleStruct);
196 impl_cast_method!(as_tuple: Tuple => &'a dyn Tuple);
197 impl_cast_method!(as_list: List => &'a dyn List);
198 impl_cast_method!(as_array: Array => &'a dyn Array);
199 impl_cast_method!(as_map: Map => &'a dyn Map);
200 impl_cast_method!(as_set: Set => &'a dyn Set);
201 impl_cast_method!(as_enum: Enum => &'a dyn Enum);
202 impl_cast_method!(as_opaque: Opaque => &'a dyn PartialReflect);
203}
204
205pub enum ReflectMut<'a> {
214 Struct(&'a mut dyn Struct),
215 TupleStruct(&'a mut dyn TupleStruct),
216 Tuple(&'a mut dyn Tuple),
217 List(&'a mut dyn List),
218 Array(&'a mut dyn Array),
219 Map(&'a mut dyn Map),
220 Set(&'a mut dyn Set),
221 Enum(&'a mut dyn Enum),
222 #[cfg(feature = "functions")]
223 Function(&'a mut dyn Function),
224 Opaque(&'a mut dyn PartialReflect),
225}
226impl_reflect_kind_conversions!(ReflectMut<'_>);
227
228impl<'a> ReflectMut<'a> {
229 impl_cast_method!(as_struct: Struct => &'a mut dyn Struct);
230 impl_cast_method!(as_tuple_struct: TupleStruct => &'a mut dyn TupleStruct);
231 impl_cast_method!(as_tuple: Tuple => &'a mut dyn Tuple);
232 impl_cast_method!(as_list: List => &'a mut dyn List);
233 impl_cast_method!(as_array: Array => &'a mut dyn Array);
234 impl_cast_method!(as_map: Map => &'a mut dyn Map);
235 impl_cast_method!(as_set: Set => &'a mut dyn Set);
236 impl_cast_method!(as_enum: Enum => &'a mut dyn Enum);
237 impl_cast_method!(as_opaque: Opaque => &'a mut dyn PartialReflect);
238}
239
240pub enum ReflectOwned {
249 Struct(Box<dyn Struct>),
250 TupleStruct(Box<dyn TupleStruct>),
251 Tuple(Box<dyn Tuple>),
252 List(Box<dyn List>),
253 Array(Box<dyn Array>),
254 Map(Box<dyn Map>),
255 Set(Box<dyn Set>),
256 Enum(Box<dyn Enum>),
257 #[cfg(feature = "functions")]
258 Function(Box<dyn Function>),
259 Opaque(Box<dyn PartialReflect>),
260}
261impl_reflect_kind_conversions!(ReflectOwned);
262
263impl ReflectOwned {
264 impl_cast_method!(into_struct: Struct => Box<dyn Struct>);
265 impl_cast_method!(into_tuple_struct: TupleStruct => Box<dyn TupleStruct>);
266 impl_cast_method!(into_tuple: Tuple => Box<dyn Tuple>);
267 impl_cast_method!(into_list: List => Box<dyn List>);
268 impl_cast_method!(into_array: Array => Box<dyn Array>);
269 impl_cast_method!(into_map: Map => Box<dyn Map>);
270 impl_cast_method!(into_set: Set => Box<dyn Set>);
271 impl_cast_method!(into_enum: Enum => Box<dyn Enum>);
272 impl_cast_method!(into_value: Opaque => Box<dyn PartialReflect>);
273}
274
275#[cfg(test)]
276mod tests {
277 use alloc::vec;
278 use std::collections::HashSet;
279
280 use super::*;
281
282 #[test]
283 fn should_cast_ref() {
284 let value = vec![1, 2, 3];
285
286 let result = value.reflect_ref().as_list();
287 assert!(result.is_ok());
288
289 let result = value.reflect_ref().as_array();
290 assert!(matches!(
291 result,
292 Err(ReflectKindMismatchError {
293 expected: ReflectKind::Array,
294 received: ReflectKind::List
295 })
296 ));
297 }
298
299 #[test]
300 fn should_cast_mut() {
301 let mut value: HashSet<i32> = HashSet::default();
302
303 let result = value.reflect_mut().as_set();
304 assert!(result.is_ok());
305
306 let result = value.reflect_mut().as_map();
307 assert!(matches!(
308 result,
309 Err(ReflectKindMismatchError {
310 expected: ReflectKind::Map,
311 received: ReflectKind::Set
312 })
313 ));
314 }
315
316 #[test]
317 fn should_cast_owned() {
318 let value = Box::new(Some(123));
319
320 let result = value.reflect_owned().into_enum();
321 assert!(result.is_ok());
322
323 let value = Box::new(Some(123));
324
325 let result = value.reflect_owned().into_struct();
326 assert!(matches!(
327 result,
328 Err(ReflectKindMismatchError {
329 expected: ReflectKind::Struct,
330 received: ReflectKind::Enum
331 })
332 ));
333 }
334}