1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
//! A macro for easily defining structs that act like C enums.
//!
//! The [`c_enum!`] macro generates structs that behave roughly like a C enum:
//! they have a set of constants that have integer values but can be assigned
//! integer values that don't correspond to any of the existing names.
//!
//! # Examples
//! ```
//! use c_enum::c_enum;
//!
//! c_enum! {
//!     #[derive(Copy, Clone, PartialEq, Eq, Hash)]
//!     pub enum MyEnum: u32 {
//!         A,
//!         B = 5,
//!     }
//! }
//!
//! let v1 = MyEnum::A;       // declared variant
//! let v2 = MyEnum::from(3); // also supports variants that are not declared
//!
//! match v1 { // we can match if we derive PartialEq
//!     MyEnum::A => println!("got an A"),
//!     MyEnum::B => println!("got a B"),
//!
//!     // We still need to handle other variants
//!     _ => println!("got another variant"),
//! }
//! ```
//!
//! # Visibility
//! The `c_enum!` macro supports visibility, just like you would do for a normal
//! rust enum.
//!
//! ```
//! # #[macro_use]
//! # extern crate c_enum;
//! #
//! mod example {
//!     c_enum! {
//!         pub enum Enum1: u8 {
//!             A,
//!         }
//!     }
//!
//!     c_enum! {
//! #       pub
//!         enum Enum2: u8 {
//!             B,
//!         }
//!     }
//! }
//!
//! # fn main() {
//! let val1 = example::Enum1::A;
//! let val2 = example::Enum2::B; // error: struct `Enum2` is private
//! # }
//! ```
//!
//! # Attributes
//! Attributes can be added to the generated type or variants as normal. Note
//! that the variants are converted to constants so macros expecting an enum
//! variant will not work.
//!
//! ## Applying Attributes to Generated `impl` Blocks
//! Sometimes you need to apply attributes to the generated `impl` blocks (e.g.
//! to silence warnings). `c_enum!` supports adding an extra `impl` block at the
//! end and will apply those attributes to the generated `impl` block.
//! ```
//! #![deny(missing_docs)]
//! # //! crate docs...
//! # use c_enum::c_enum;
//!
//! c_enum! {
//!     /// This crate requires that all items be documented.
//!     ///
//!     /// However, we don't want to document the members of this enum for one
//!     /// reason or another.
//!     pub enum SomeCEnum : u32 {
//!         A = 0,
//!         B
//!     }
//!
//!     // So we attach the #[allow] directive to this extra impl block here
//!     // and it will be added to the one generated by the macro.
//!     #[allow(missing_docs)]
//!     impl {}
//! }
//! ```
//!
//! # Representation
//! It is valid to add a `#[repr(C)]` or `#[repr(transparent)]` attribute to the
//! generated type. The generated type is guaranteed to be a newtype whose only
//! member is the inner type.
//!
//! # Value Assignment
//! By default, enum values are assigned like they would be for a C enum: the
//! first variant is 0 and subsequent variants increase by 1 unless assigned a
//! value.
//!
//! ```
//! # #[macro_use]
//! # extern crate c_enum;
//! #
//! c_enum! {
//!     pub enum Enum: u32 {
//!         A,     // value of 0
//!         B,     // value of 1
//!         C = 5, // value of 5
//!         D,     // value of 6
//!     }
//! }
//! # fn main() {}
//! ```
//!
//! ## Non-String Inner Types
//! It is also possible to define enum types whose inner value is not an
//! integer.
//!
//! ```
//! # #[macro_use]
//! # extern crate c_enum;
//! #
//! c_enum! {
//!     pub enum StringEnum: &'static str {
//!         Hello = "Hello",
//!         World = "World",
//!     }
//! }
//! # fn main() {}
//! ```
//!
//! Note that at this time generics are not supported so any inner value type
//! must be both concrete and `'static`. Furthermore, you will need to assign a
//! value to each variant of such an enum.
//!
//! # What's implemented by `c_enum!`
//! The [`c_enum!`] macro implements some traits by default, but leaves the rest
//! available for you to choose the semantics of the rest.
//!
//! ## Formatting
//! - [`Debug`], but only if the inner type implements [`PartialEq`] and
//!   [`Debug`].
//!
//! ## Conversion
//! - [`From`] to convert from the inner type and vice versa.
//!
//! # Generated Code
//! ```
//! # #[macro_use]
//! # extern crate c_enum;
//! #
//! c_enum! {
//!     #[repr(transparent)]
//!     #[derive(Copy, Clone, PartialEq, Eq, Hash)]
//!     enum Enum: u32 {
//!         A,
//!         B = 5,
//!     }
//! }
//! # fn main() {}
//! ```
//! is expanded into (roughly)
//! ```
//! # macro_rules! ignore { {$( $tt:tt )*} => {} }
//! # #[macro_use]
//! # extern crate c_enum;
//! #
//! #[repr(transparent)]
//! #[derive(Copy, Clone, PartialEq, Eq, Hash)]
//! struct Enum(u32);
//!
//! impl Enum {
//!     pub const A: Self = Self(0);
//!     pub const B: Self = Self(5);
//! }
//!
//! # ignore! {
//! impl core::fmt::Debug for Enum
//! where
//!     u32: core::cmp::PartialEq
//! {
//!     ...
//! }
//!
//! // more trait impls...
//! # }
//! # fn main() {}
//! ```
//!
//! # Motivation
//! When writing bindings for C libraries which use enums there are a few
//! options for declaring rust versions of C enums.
//! - Use a rust enum.
//! - Use a raw integer and a bunch of constants.
//! - Use a newtype and a set of constants.
//!
//! All of them have use cases for which they are valid:
//! - Rust enums work when calling from rust code into C code. The one caveat
//!   here being that if the underlying C library adds a new variant but the
//!   rust wrapper does not then users of the rust library are stuck. Another
//!   case that is valid is if it is known that no new variants will be added to
//!   the underlying C enum and the library is ok with either UB or doing
//!   conversions at the API boundary.
//! - Raw integers and constants is useful for autogenerated bindings that want
//!   to exactly match the layout of the C headers.
//! - A newtype + constants is suitable for the remaining cases. It still
//!   behaves similar to a rust enum but matches the actual semantics of C
//!   enums. It also continues to work if the C library adds new variants and
//!   the rust wrapper is not updated.
//!
//! This crate is a generator for the third option.
//!
//! [`Debug`]: core::fmt::Debug
//! [`PartialEq`]: core::cmp::PartialEq

#![no_std]
#![cfg_attr(docsrs, feature(doc_cfg))]

extern crate self as c_enum;

#[cfg(doc)]
#[doc = include_str!("../README.md")]
mod readme {}

#[doc(hidden)]
/// A trait that is automatically implemented for all C enums.
pub trait CEnum: From<Self::Inner> + Into<Self::Inner> {
    /// The inner type of this enum.
    type Inner;

    /// Get the string name corresponding to the current value, if there is one.
    fn variant_label(&self) -> Option<&'static str>
    where
        Self::Inner: PartialEq;
}

/// The macro used to generate the C enum structure.
///
/// See the [crate level docs](crate) for complete documentation.
#[macro_export]
macro_rules! c_enum {
    {
        $( #[$attr:meta] )*
        $vis:vis enum $name:ident : $inner:ty {
            $(
                $( #[ $field_attr:meta ] )*
                $field:ident $( = $value:expr )?
            ),* $(,)?
        }

        $(
            $( #[$iattr:meta] )*
            impl {}
        )?
    } => {
        $crate::__c_enum_no_debug! {
            $( #[$attr] )*
            $vis enum $name : $inner {
                $(
                    $( #[ $field_attr ] )*
                    $field $( = $value )?
                ),*
            }

            $(
                $( #[$iattr] )*
                impl {}
            )?
        }

        impl ::core::fmt::Debug for $name
        where
            $inner: ::core::fmt::Debug,
            $inner: ::core::cmp::PartialEq
        {
            fn fmt(
                &self,
                f: &mut ::core::fmt::Formatter<'_>
            ) -> ::core::fmt::Result {
                use $crate::CEnum;

                match self.variant_label() {
                    Some(variant) => {
                        f.write_fmt(::core::format_args!(
                            "{}::{}", ::core::stringify!($name), variant
                        ))
                    },
                    None => f
                        .debug_tuple(::core::stringify!($name))
                        .field(&self.0)
                        .finish()
                }
            }
        }
    };
}

// TODO: not sure if this is worth adding to the public API.
/// The macro used to generate the C enum structure.
///
/// This version does not generate a [`Debug`] impl.
///
/// See the [crate level docs](crate) for complete documentation.
///
/// [`Debug`]: core::fmt::Debug
#[macro_export]
#[doc(hidden)]
macro_rules! __c_enum_no_debug {
    {
        $( #[$attr:meta] )*
        $vis:vis enum $name:ident : $inner:ty {
            $(
                $( #[ $field_attr:meta ] )*
                $field:ident $( = $value:expr )?
            ),* $(,)?
        }

        $(
            $( #[$iattr:meta] )*
            impl {}
        )?
    } => {
        $( #[$attr] )*
        $vis struct $name(pub $inner);

        #[allow(non_upper_case_globals)]
        $( $( #[$iattr] )* )?
        impl $name {
            $crate::__c_enum_impl!(
                impl(decl_variants, $name, $inner, 0)
                $(
                    $( #[$field_attr] )*
                    $field $( = $value )?,
                )*
            );
        }

        #[automatically_derived]
        impl From<$inner> for $name {
            fn from(value: $inner) -> Self {
                Self(value)
            }
        }

        #[automatically_derived]
        impl From<$name> for $inner {
            fn from(value: $name) -> Self {
                value.0
            }
        }

        #[automatically_derived]
        impl $crate::CEnum for $name {
            type Inner = $inner;

            fn variant_label(&self) -> Option<&'static str>
            where
                Self::Inner: PartialEq
            {
                Some(match &self.0 {
                    $( value if Self::$field.0 == *value => ::core::stringify!($field), )*
                    _ => return None,
                })
            }
        }
    };
}

/// Helper macro for defining stuff in c_enum.
///
/// These could be a bunch of different macros but those would clutter up the
/// import namespace when using something like rust-analyzer. By using a single
/// internal macro we can avoid that.
#[doc(hidden)]
#[macro_export]
macro_rules! __c_enum_impl {
    (impl(first_expr) $first:expr $( , $rest:expr )*) => {
        $first
    };

    (impl(decl_variants, $name:ident, $inner:ty, $default:expr)) => {};
    (
        impl(decl_variants, $name:ident, $inner:ty, $default:expr)
        $( #[$fattr:meta] )*
        $field:ident $( = $fvalue:expr )?
        $( ,
            $( #[$rattr:meta] )*
            $frest:ident $( = $frest_val:expr )?
        )*
        $(,)?
    ) => {
        $( #[$fattr] )*
        #[allow(non_upper_case_globals)]
        pub const $field: Self = Self($crate::__c_enum_impl!(
            impl(first_expr) $( $fvalue, )? $default));

        $crate::__c_enum_impl!(
            impl(decl_variants, $name, $inner, Self::$field.0 + 1)
            $( $( #[$rattr] )* $frest $( = $frest_val )?, )*
        );
    }
}

// This needs to be after all the macro definitions.
/// This module shows an example of code generated by the macro.
///
/// The source code of this module is
/// ```
#[doc = include_str!("example.rs")]
/// ```
#[cfg(doc)]
#[cfg_attr(docsrs, doc(cfg(doc)))]
pub mod example;