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