facet_reflect/partial/partial_api/
eenum.rs

1use super::*;
2
3////////////////////////////////////////////////////////////////////////////////////////////////////
4// Enum variant selection
5////////////////////////////////////////////////////////////////////////////////////////////////////
6impl<'facet, const BORROW: bool> Partial<'facet, BORROW> {
7    /// Get the currently selected variant for an enum
8    pub fn selected_variant(&self) -> Option<Variant> {
9        let frame = self.frames().last()?;
10
11        match &frame.tracker {
12            Tracker::Enum { variant, .. } => Some(**variant),
13            _ => None,
14        }
15    }
16
17    /// Find a variant by name in the current enum
18    pub fn find_variant(&self, variant_name: &str) -> Option<(usize, &'static Variant)> {
19        let frame = self.frames().last()?;
20
21        if let Type::User(UserType::Enum(enum_def)) = frame.shape.ty {
22            enum_def
23                .variants
24                .iter()
25                .enumerate()
26                .find(|(_, v)| v.name == variant_name)
27        } else {
28            None
29        }
30    }
31
32    /// Assuming the current frame is an enum, this selects a variant by index
33    /// (0-based, in declaration order).
34    ///
35    /// For example:
36    ///
37    /// ```rust,no_run
38    /// enum E { A, B, C }
39    /// ```
40    ///
41    /// Calling `select_nth_variant(2)` would select variant `C`.
42    ///
43    /// This will return an error if the current frame is anything other than fully-uninitialized.
44    /// In other words, it's not possible to "switch to a different variant" once you've selected one.
45    ///
46    /// This does _not_ push a frame on the stack.
47    pub fn select_nth_variant(mut self, index: usize) -> Result<Self, ReflectError> {
48        let frame = self.frames().last().unwrap();
49        let enum_type = frame.get_enum_type()?;
50
51        if index >= enum_type.variants.len() {
52            return Err(ReflectError::OperationFailed {
53                shape: frame.shape,
54                operation: "variant index out of bounds",
55            });
56        }
57        let variant = &enum_type.variants[index];
58
59        self.select_variant_internal(&enum_type, variant)?;
60        Ok(self)
61    }
62
63    /// Pushes a variant for enum initialization by name
64    ///
65    /// See [Self::select_nth_variant] for more notes.
66    pub fn select_variant_named(mut self, variant_name: &str) -> Result<Self, ReflectError> {
67        let frame = self.frames_mut().last_mut().unwrap();
68        let enum_type = frame.get_enum_type()?;
69
70        let Some(variant) = enum_type.variants.iter().find(|v| v.name == variant_name) else {
71            return Err(ReflectError::OperationFailed {
72                shape: frame.shape,
73                operation: "No variant found with the given name",
74            });
75        };
76
77        self.select_variant_internal(&enum_type, variant)?;
78        Ok(self)
79    }
80
81    /// Selects a given enum variant by discriminant. If none of the variants
82    /// of the frame's enum have that discriminant, this returns an error.
83    ///
84    /// See [Self::select_nth_variant] for more notes.
85    pub fn select_variant(mut self, discriminant: i64) -> Result<Self, ReflectError> {
86        // Check all invariants early before making any changes
87        let frame = self.frames().last().unwrap();
88
89        // Check that we're dealing with an enum
90        let enum_type = match frame.shape.ty {
91            Type::User(UserType::Enum(e)) => e,
92            _ => {
93                return Err(ReflectError::WasNotA {
94                    expected: "enum",
95                    actual: frame.shape,
96                });
97            }
98        };
99
100        // Find the variant with the matching discriminant
101        let Some(variant) = enum_type
102            .variants
103            .iter()
104            .find(|v| v.discriminant == Some(discriminant))
105        else {
106            return Err(ReflectError::OperationFailed {
107                shape: frame.shape,
108                operation: "No variant found with the given discriminant",
109            });
110        };
111
112        // Update the frame tracker to select the variant
113        self.select_variant_internal(&enum_type, variant)?;
114
115        Ok(self)
116    }
117}