Skip to main content

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