enum_repr_conv/lib.rs
1#![deny(missing_docs)]
2//! # enum_repr_conv
3//! `enum_repr_conv` is a proc-macro library that provides a convenient attribute-style `repr_conv()` macro
4//! to specify a primitive integer type used for representing variants of the annotated fieldless enum as
5//! values of this type.
6//!
7//! ## Description
8//! `enum_repr_conv` bridges the gap between C-style enums and fieldless enums in Rust that can be
9//! represented using a chosen primitive integer type. It implements conversions from enum variants into
10//! integer values (infallible through [`std::convert::From`](https://doc.rust-lang.org/std/convert/trait.From.html))
11//! and vice versa (fallible through [`std::convert::TryFrom`](https://doc.rust-lang.org/std/convert/trait.TryFrom.html)).
12//! This functionality is provided via `repr_conv(<type>)` macro that mimics the syntax and behavior of
13//! [`repr(u*)/repr(i*)`](https://doc.rust-lang.org/nomicon/other-reprs.html#repru-repri) data layout
14//! attributes but additionally provides practical and sensible implementations of common conversion traits.
15
16use proc_macro::TokenStream;
17
18use crate::parse::parse;
19use crate::produce::produce;
20use crate::transform::transform;
21
22mod parse;
23mod produce;
24mod transform;
25
26/// An attribute macro that mimics the syntax and behavior of `repr(u*)`/`repr(i*)` but additionally
27/// implements [`std::convert::From`](https://doc.rust-lang.org/std/convert/trait.From.html) and
28/// [`std::convert::TryFrom`](https://doc.rust-lang.org/std/convert/trait.TryFrom.html)
29/// traits to provide practical and sensible conversions between annontated enum variants and respective
30/// integer values.
31///
32/// [`repr_conv`](macro@repr_conv) accepts a single parameter which is a primitive integer type.
33///
34/// ```rust
35/// # use enum_repr_conv::repr_conv;
36/// #[repr_conv(u16)]
37/// #[derive(Debug, PartialEq, Eq)]
38/// enum SupportedPorts {
39/// FTP = 21,
40/// SSH, // = 22
41/// HTTP = 80,
42/// HTTPS = 443,
43/// }
44///
45/// // we can get a u16 for the FTP port easily...
46/// assert_eq!(u16::from(SupportedPorts::FTP), 21);
47/// //... and for the SSH port too
48/// assert_eq!(u16::from(SupportedPorts::SSH), 22);
49/// // HTTP port is supported and so conversion succeeds
50/// assert_eq!(SupportedPorts::try_from(80).unwrap(), SupportedPorts::HTTP);
51/// // Gopher is not supported; who needs it in 2025?!
52/// assert!(SupportedPorts::try_from(70).is_err());
53/// ```
54#[proc_macro_attribute]
55pub fn repr_conv(attr: TokenStream, item: TokenStream) -> TokenStream {
56 match parse(attr.into(), item.into()) {
57 Ok(parsed) => {
58 let transformed = transform(parsed);
59 let code = produce(transformed);
60
61 code.into()
62 }
63 Err(err) => err.to_compile_error().into(),
64 }
65}