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,
139    pub received: ReflectKind,
141}
142
143macro_rules! impl_cast_method {
144    ($name:ident : Opaque => $retval:ty) => {
145        #[doc = "Attempts a cast to a [`PartialReflect`] trait object."]
146        #[doc = "\n\nReturns an error if `self` is not the [`Self::Opaque`] variant."]
147        pub fn $name(self) -> Result<$retval, ReflectKindMismatchError> {
148            match self {
149                Self::Opaque(value) => Ok(value),
150                _ => Err(ReflectKindMismatchError {
151                    expected: ReflectKind::Opaque,
152                    received: self.kind(),
153                }),
154            }
155        }
156    };
157    ($name:ident : $kind:ident => $retval:ty) => {
158        #[doc = concat!("Attempts a cast to a [`", stringify!($kind), "`] trait object.")]
159        #[doc = concat!("\n\nReturns an error if `self` is not the [`Self::", stringify!($kind), "`] variant.")]
160        pub fn $name(self) -> Result<$retval, ReflectKindMismatchError> {
161            match self {
162                Self::$kind(value) => Ok(value),
163                _ => Err(ReflectKindMismatchError {
164                    expected: ReflectKind::$kind,
165                    received: self.kind(),
166                }),
167            }
168        }
169    };
170}
171
172pub enum ReflectRef<'a> {
181    Struct(&'a dyn Struct),
185    TupleStruct(&'a dyn TupleStruct),
189    Tuple(&'a dyn Tuple),
193    List(&'a dyn List),
197    Array(&'a dyn Array),
201    Map(&'a dyn Map),
205    Set(&'a dyn Set),
209    Enum(&'a dyn Enum),
213    #[cfg(feature = "functions")]
217    Function(&'a dyn Function),
218    Opaque(&'a dyn PartialReflect),
222}
223
224impl_reflect_kind_conversions!(ReflectRef<'_>);
225
226impl<'a> ReflectRef<'a> {
227    impl_cast_method!(as_struct: Struct => &'a dyn Struct);
228    impl_cast_method!(as_tuple_struct: TupleStruct => &'a dyn TupleStruct);
229    impl_cast_method!(as_tuple: Tuple => &'a dyn Tuple);
230    impl_cast_method!(as_list: List => &'a dyn List);
231    impl_cast_method!(as_array: Array => &'a dyn Array);
232    impl_cast_method!(as_map: Map => &'a dyn Map);
233    impl_cast_method!(as_set: Set => &'a dyn Set);
234    impl_cast_method!(as_enum: Enum => &'a dyn Enum);
235    impl_cast_method!(as_opaque: Opaque => &'a dyn PartialReflect);
236}
237
238pub enum ReflectMut<'a> {
247    Struct(&'a mut dyn Struct),
251    TupleStruct(&'a mut dyn TupleStruct),
255    Tuple(&'a mut dyn Tuple),
259    List(&'a mut dyn List),
263    Array(&'a mut dyn Array),
267    Map(&'a mut dyn Map),
271    Set(&'a mut dyn Set),
275    Enum(&'a mut dyn Enum),
279    #[cfg(feature = "functions")]
280    Function(&'a mut dyn Function),
284    Opaque(&'a mut dyn PartialReflect),
288}
289
290impl_reflect_kind_conversions!(ReflectMut<'_>);
291
292impl<'a> ReflectMut<'a> {
293    impl_cast_method!(as_struct: Struct => &'a mut dyn Struct);
294    impl_cast_method!(as_tuple_struct: TupleStruct => &'a mut dyn TupleStruct);
295    impl_cast_method!(as_tuple: Tuple => &'a mut dyn Tuple);
296    impl_cast_method!(as_list: List => &'a mut dyn List);
297    impl_cast_method!(as_array: Array => &'a mut dyn Array);
298    impl_cast_method!(as_map: Map => &'a mut dyn Map);
299    impl_cast_method!(as_set: Set => &'a mut dyn Set);
300    impl_cast_method!(as_enum: Enum => &'a mut dyn Enum);
301    impl_cast_method!(as_opaque: Opaque => &'a mut dyn PartialReflect);
302}
303
304pub enum ReflectOwned {
313    Struct(Box<dyn Struct>),
317    TupleStruct(Box<dyn TupleStruct>),
321    Tuple(Box<dyn Tuple>),
325    List(Box<dyn List>),
329    Array(Box<dyn Array>),
333    Map(Box<dyn Map>),
337    Set(Box<dyn Set>),
341    Enum(Box<dyn Enum>),
345    #[cfg(feature = "functions")]
349    Function(Box<dyn Function>),
350    Opaque(Box<dyn PartialReflect>),
354}
355
356impl_reflect_kind_conversions!(ReflectOwned);
357
358impl ReflectOwned {
359    impl_cast_method!(into_struct: Struct => Box<dyn Struct>);
360    impl_cast_method!(into_tuple_struct: TupleStruct => Box<dyn TupleStruct>);
361    impl_cast_method!(into_tuple: Tuple => Box<dyn Tuple>);
362    impl_cast_method!(into_list: List => Box<dyn List>);
363    impl_cast_method!(into_array: Array => Box<dyn Array>);
364    impl_cast_method!(into_map: Map => Box<dyn Map>);
365    impl_cast_method!(into_set: Set => Box<dyn Set>);
366    impl_cast_method!(into_enum: Enum => Box<dyn Enum>);
367    impl_cast_method!(into_value: Opaque => Box<dyn PartialReflect>);
368}
369
370#[cfg(test)]
371mod tests {
372    use alloc::vec;
373    use std::collections::HashSet;
374
375    use super::*;
376
377    #[test]
378    fn should_cast_ref() {
379        let value = vec![1, 2, 3];
380
381        let result = value.reflect_ref().as_list();
382        assert!(result.is_ok());
383
384        let result = value.reflect_ref().as_array();
385        assert!(matches!(
386            result,
387            Err(ReflectKindMismatchError {
388                expected: ReflectKind::Array,
389                received: ReflectKind::List
390            })
391        ));
392    }
393
394    #[test]
395    fn should_cast_mut() {
396        let mut value: HashSet<i32> = HashSet::default();
397
398        let result = value.reflect_mut().as_set();
399        assert!(result.is_ok());
400
401        let result = value.reflect_mut().as_map();
402        assert!(matches!(
403            result,
404            Err(ReflectKindMismatchError {
405                expected: ReflectKind::Map,
406                received: ReflectKind::Set
407            })
408        ));
409    }
410
411    #[test]
412    fn should_cast_owned() {
413        let value = Box::new(Some(123));
414
415        let result = value.reflect_owned().into_enum();
416        assert!(result.is_ok());
417
418        let value = Box::new(Some(123));
419
420        let result = value.reflect_owned().into_struct();
421        assert!(matches!(
422            result,
423            Err(ReflectKindMismatchError {
424                expected: ReflectKind::Struct,
425                received: ReflectKind::Enum
426            })
427        ));
428    }
429}