open_enum/lib.rs
1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4#![no_std]
5#![forbid(unsafe_code)]
6
7//! Provides the [`open_enum`] macro.
8
9/// This macro creates an underlying struct that behaves like an enum, without
10/// the undefined behavior of trying to match with a value outside of the enum.
11/// The actual object created is a `#[repr(transparent)]` struct with a `pub` const
12/// value. See comment in example below for an example of the underlying
13/// structure.
14///
15/// This macro implements the following traits: `Copy`, `Clone`, `Debug`, `Eq`,
16/// `PartialEq`, `Hash`, `Ord`, `PartialOrd`.
17///
18/// An example usage case for this macro is for protocols, when you want to use
19/// an enum as a field in a struct that represents a specific type, like u16 or
20/// u32. You are also able to convert to/from bytes with this typed enum.
21///
22/// # Examples
23///
24/// ```
25/// # #[macro_use] extern crate open_enum; fn main() {
26/// use open_enum::open_enum;
27/// open_enum! {
28/// #[expect(dead_code)] // This will apply to the generated struct defn
29/// pub enum ExampleEnumName: u32 {
30/// #![expect(missing_docs)] // This will apply to all subfields of the enum
31/// THIS_IS_AN_ENUM = 32,
32/// }
33/// }
34/// // Expands to:
35/// //
36/// // #[repr(transparent)]
37// // #[derive(Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
38/// // #[expect(dead_code)]
39/// // struct ExampleEnumName(u32);
40/// //
41/// // #[expect(missing_docs)]
42/// // impl ExampleEnumName {
43/// // pub const THIS_IS_AN_ENUM: ExampleEnumName = ExampleEnumName(0)
44/// // }
45///
46/// // To access an element in ExampleEnumName
47/// let example_enum = ExampleEnumName::THIS_IS_AN_ENUM;
48///
49/// assert_eq!(example_enum.0, 32);
50///
51/// let number: u32 = example_enum.0; // enum value is type u32
52/// # }
53/// ```
54#[macro_export]
55macro_rules! open_enum {
56 (
57 $(#[$a:meta])*
58 $v:vis enum $name:ident : $storage:ty {
59 $(#![$implattr:meta])*
60 $(
61 $(#[$vattr:meta])*
62 $variant:ident = $value:expr,
63 )*
64 }
65 ) => {
66 #[derive(Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
67 #[repr(transparent)]
68 $(#[$a])*
69 $v struct $name(pub $storage);
70 $(#[$implattr])*
71 impl $name {
72 $(
73 $(#[$vattr])*
74 pub const $variant: $name = $name($value);
75 )*
76 }
77 impl ::core::fmt::Debug for $name {
78 fn fmt(&self, fmt: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
79 #![allow(unreachable_patterns)]
80 let s = match *self {
81 $( Self::$variant => stringify!($variant), )*
82 _ => {
83 return ::core::fmt::Debug::fmt(&self.0, fmt);
84 }
85 };
86 fmt.pad(s)
87 }
88 }
89 }
90}