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