facet_core/types/ty/
enum_.rs

1use super::{Repr, StructType};
2
3/// Fields for enum types
4#[derive(Clone, Copy, Debug)]
5#[repr(C)]
6pub struct EnumType {
7    /// Representation of the enum's data
8    pub repr: Repr,
9
10    /// representation of the enum's discriminant (u8, u16, etc.)
11    pub enum_repr: EnumRepr,
12
13    /// all variants for this enum
14    pub variants: &'static [Variant],
15}
16
17impl EnumType {
18    /// Returns a builder for EnumDef
19    pub const fn builder() -> EnumDefBuilder {
20        EnumDefBuilder::new()
21    }
22}
23
24/// Builder for EnumDef
25pub struct EnumDefBuilder {
26    repr: Option<Repr>,
27    enum_repr: Option<EnumRepr>,
28    variants: Option<&'static [Variant]>,
29}
30
31impl EnumDefBuilder {
32    /// Creates a new EnumDefBuilder
33    #[allow(clippy::new_without_default)]
34    pub const fn new() -> Self {
35        Self {
36            repr: None,
37            enum_repr: None,
38            variants: None,
39        }
40    }
41
42    /// Sets the representation for the EnumDef
43    pub const fn repr(mut self, repr: Repr) -> Self {
44        self.repr = Some(repr);
45        self
46    }
47
48    /// Sets the discriminant representation for the EnumDef
49    pub const fn enum_repr(mut self, enum_repr: EnumRepr) -> Self {
50        self.enum_repr = Some(enum_repr);
51        self
52    }
53
54    /// Sets the variants for the EnumDef
55    pub const fn variants(mut self, variants: &'static [Variant]) -> Self {
56        self.variants = Some(variants);
57        self
58    }
59
60    /// Builds the EnumDef
61    pub const fn build(self) -> EnumType {
62        EnumType {
63            repr: self.repr.unwrap(),
64            enum_repr: self.enum_repr.unwrap(),
65            variants: self.variants.unwrap(),
66        }
67    }
68}
69
70/// Describes a variant of an enum
71#[derive(Clone, Copy, Debug)]
72#[repr(C)]
73pub struct Variant {
74    /// Name of the variant, e.g. `Foo` for `enum FooBar { Foo, Bar }`
75    pub name: &'static str,
76
77    /// Discriminant value (if available). Might fit in a u8, etc.
78    pub discriminant: Option<i64>,
79
80    /// Attributes set for this variant via the derive macro
81    pub attributes: &'static [VariantAttribute],
82
83    /// Fields for this variant (empty if unit, number-named if tuple).
84    /// IMPORTANT: the offset for the fields already takes into account the size & alignment of the
85    /// discriminant.
86    pub data: StructType,
87
88    /// Doc comment for the variant
89    pub doc: &'static [&'static str],
90}
91
92impl Variant {
93    /// Returns a builder for Variant
94    pub const fn builder() -> VariantBuilder {
95        VariantBuilder::new()
96    }
97
98    /// Checks whether the `Variant` has an attribute of form `VariantAttribute::Arbitrary` with the
99    /// given content.
100    #[inline]
101    pub fn has_arbitrary_attr(&self, content: &'static str) -> bool {
102        self.attributes
103            .contains(&VariantAttribute::Arbitrary(content))
104    }
105}
106
107/// Builder for Variant
108pub struct VariantBuilder {
109    name: Option<&'static str>,
110    discriminant: Option<i64>,
111    attributes: &'static [VariantAttribute],
112    data: Option<StructType>,
113    doc: &'static [&'static str],
114}
115
116impl VariantBuilder {
117    /// Creates a new VariantBuilder
118    #[allow(clippy::new_without_default)]
119    pub const fn new() -> Self {
120        Self {
121            name: None,
122            discriminant: None,
123            attributes: &[],
124            data: None,
125            doc: &[],
126        }
127    }
128
129    /// Sets the name for the Variant
130    pub const fn name(mut self, name: &'static str) -> Self {
131        self.name = Some(name);
132        self
133    }
134
135    /// Sets the discriminant for the Variant
136    pub const fn discriminant(mut self, discriminant: i64) -> Self {
137        self.discriminant = Some(discriminant);
138        self
139    }
140
141    /// Sets the attributes for the variant
142    pub const fn attributes(mut self, attributes: &'static [VariantAttribute]) -> Self {
143        self.attributes = attributes;
144        self
145    }
146
147    /// Sets the fields for the Variant
148    pub const fn data(mut self, data: StructType) -> Self {
149        self.data = Some(data);
150        self
151    }
152
153    /// Sets the doc comment for the Variant
154    pub const fn doc(mut self, doc: &'static [&'static str]) -> Self {
155        self.doc = doc;
156        self
157    }
158
159    /// Builds the Variant
160    pub const fn build(self) -> Variant {
161        Variant {
162            name: self.name.unwrap(),
163            discriminant: self.discriminant,
164            attributes: self.attributes,
165            data: self.data.unwrap(),
166            doc: self.doc,
167        }
168    }
169}
170
171/// An attribute that can be set on an enum variant
172#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
173#[repr(C)]
174pub enum VariantAttribute {
175    /// Custom field attribute containing arbitrary text
176    Arbitrary(&'static str),
177}
178
179/// All possible representations for Rust enums — ie. the type/size of the discriminant
180#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
181#[repr(C)]
182pub enum EnumRepr {
183    /// Special-case representation discriminated by zeros under non-nullable pointer
184    ///
185    /// See: <https://rust-lang.github.io/unsafe-code-guidelines/layout/enums.html#discriminant-elision-on-option-like-enums>
186    RustNPO,
187    /// u8 representation (#[repr(u8)])
188    U8,
189    /// u16 representation (#[repr(u16)])
190    U16,
191    /// u32 representation (#[repr(u32)])
192    U32,
193    /// u64 representation (#[repr(u64)])
194    U64,
195    /// usize representation (#[repr(usize)])
196    USize,
197    /// i8 representation (#[repr(i8)])
198    I8,
199    /// i16 representation (#[repr(i16)])
200    I16,
201    /// i32 representation (#[repr(i32)])
202    I32,
203    /// i64 representation (#[repr(i64)])
204    I64,
205    /// isize representation (#[repr(isize)])
206    ISize,
207}
208
209impl EnumRepr {
210    /// Returns the enum representation for the given discriminant type
211    ///
212    /// NOTE: only supports unsigned discriminants
213    ///
214    /// # Panics
215    ///
216    /// Panics if the size of the discriminant size is not 1, 2, 4, or 8 bytes.
217    pub const fn from_discriminant_size<T>() -> Self {
218        match core::mem::size_of::<T>() {
219            1 => EnumRepr::U8,
220            2 => EnumRepr::U16,
221            4 => EnumRepr::U32,
222            8 => EnumRepr::U64,
223            _ => panic!("Invalid enum size"),
224        }
225    }
226}