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}