facet_reflect/wip/
enum_.rs

1use facet_core::{Def, FieldError, Variant};
2#[cfg(feature = "log")]
3use owo_colors::OwoColorize;
4
5use crate::trace;
6use crate::{ISet, ReflectError, Wip};
7
8impl Wip<'_> {
9    /// Selects a variant of an enum by index.
10    ///
11    /// # Arguments
12    ///
13    /// * `index` - The index of the variant to select.
14    ///
15    /// # Returns
16    ///
17    /// * `Ok(Self)` if the variant was successfully selected.
18    /// * `Err(ReflectError)` if the current frame is not an enum or the variant index is out of bounds.
19    pub fn variant(mut self, index: usize) -> Result<Self, ReflectError> {
20        let frame = self.frames.last_mut().unwrap();
21        let shape = frame.shape;
22        let Def::Enum(def) = shape.def else {
23            return Err(ReflectError::WasNotA {
24                expected: "enum",
25                actual: shape,
26            });
27        };
28
29        if index >= def.variants.len() {
30            return Err(ReflectError::FieldError {
31                shape,
32                field_error: FieldError::IndexOutOfBounds,
33            });
34        }
35
36        let variant = def.variants[index];
37
38        // Reset the field initialization state since we're selecting a new variant
39        ISet::clear(&mut frame.istate.fields);
40
41        // Write the discriminant value based on the enum's representation
42        let discriminant = variant.discriminant;
43        unsafe {
44            let data_ptr = frame.data.as_mut_byte_ptr();
45            match def.repr {
46                facet_core::EnumRepr::U8 => *data_ptr = discriminant as u8,
47                facet_core::EnumRepr::U16 => *(data_ptr as *mut u16) = discriminant as u16,
48                facet_core::EnumRepr::U32 => *(data_ptr as *mut u32) = discriminant as u32,
49                facet_core::EnumRepr::U64 => *(data_ptr as *mut u64) = discriminant as u64,
50                facet_core::EnumRepr::USize => *(data_ptr as *mut usize) = discriminant as usize,
51                facet_core::EnumRepr::I8 => *(data_ptr as *mut i8) = discriminant as i8,
52                facet_core::EnumRepr::I16 => *(data_ptr as *mut i16) = discriminant as i16,
53                facet_core::EnumRepr::I32 => *(data_ptr as *mut i32) = discriminant as i32,
54                facet_core::EnumRepr::I64 => *(data_ptr as *mut i64) = discriminant,
55                facet_core::EnumRepr::ISize => *(data_ptr as *mut isize) = discriminant as isize,
56                _ => {
57                    // Default to a reasonable size for other representations
58                    *(data_ptr as *mut u32) = discriminant as u32;
59                }
60            }
61        }
62
63        // Now that we've set the discriminant, we can store the variant
64        frame.istate.variant = Some(variant);
65
66        trace!(
67            "[{}] Selecting variant {} of {} with discriminant {}",
68            self.frames.len(),
69            variant.name.blue(),
70            shape.blue(),
71            discriminant
72        );
73
74        Ok(self)
75    }
76
77    /// Selects a variant of an enum by name.
78    ///
79    /// # Arguments
80    ///
81    /// * `name` - The name of the variant to select.
82    ///
83    /// # Returns
84    ///
85    /// * `Ok(Self)` if the variant was successfully selected.
86    /// * `Err(ReflectError)` if the current frame is not an enum or no variant with the given name exists.
87    pub fn variant_named(self, name: &str) -> Result<Self, ReflectError> {
88        let frame = self.frames.last().unwrap();
89        let shape = frame.shape;
90        let Def::Enum(def) = shape.def else {
91            return Err(ReflectError::WasNotA {
92                expected: "enum",
93                actual: shape,
94            });
95        };
96
97        let index =
98            def.variants
99                .iter()
100                .position(|v| v.name == name)
101                .ok_or(ReflectError::FieldError {
102                    shape,
103                    field_error: FieldError::NoSuchField,
104                })?;
105
106        self.variant(index)
107    }
108
109    /// Finds a variant in an enum by name.
110    ///
111    /// # Arguments
112    ///
113    /// * `name` - The name of the variant to find.
114    ///
115    /// # Returns
116    ///
117    /// * `Some(index, variant)` if a variant with the given name exists.
118    /// * `None` if the current frame is not an enum or no variant with the given name exists.
119    pub fn find_variant(&self, name: &str) -> Option<(usize, Variant)> {
120        let frame = self.frames.last()?;
121        if let Def::Enum(def) = frame.shape.def {
122            def.variants
123                .iter()
124                .enumerate()
125                .find(|(_, v)| v.name == name)
126                .map(|(i, &v)| (i, v))
127        } else {
128            None
129        }
130    }
131
132    /// Returns the currently selected variant for the enum in the current frame.
133    ///
134    /// # Returns
135    ///
136    /// * `Some(variant)` if the current frame is an enum and a variant has been selected.
137    /// * `None` if the current frame is not an enum or no variant has been selected yet.
138    pub fn selected_variant(&self) -> Option<Variant> {
139        let frame = self.frames.last()?;
140        frame.istate.variant
141    }
142}