discrimin_ant/lib.rs
1//! # Discrimin-Ant
2//!
3//! Discrimin-Ant is a tiny library to make working with `enum` discriminants just a little easier.
4//!
5//! ---
6//!
7//! Discrimin-Ant was originally built to make it easier to marshal enums for use for
8//! software systems that do not or cannot use the Rust ecosystem.
9//! It is intended to be used with [Serde](https://crates.io/crates/serde) to
10//! marshal and send enums over a network or save them to a file.
11//! This can be done by implementing a custom `serde::Serialize` and
12//! `serde::Deserialize` that treats an enum as a struct or tuple instead of a
13//! variant, since the variant serialize methods only provide the index of the enum
14//! instead of its discriminant. This allows enums to be serialized in a way such
15//! that rearranging the order of enums does not change the discriminant serialized.
16//!
17//! The primary features of this crate are the `Discriminantable` trait and the
18//! `discriminant` attribute.
19//! The `discriminant` attribute is meant to take the place of the `repr`
20//! attribute on enums, and will generate a few blocks of code:
21//! - An `impl` for `Discriminantable` for the enum, using the enum's actual discriminants
22//! - A fieldless version of the enum (regardless of whether or not the enum is already fieldless)
23//! - An `impl` for `Discriminantable` on the fieldless version of the enum
24//! - Other utilities on the fieldless version to ease use
25//!
26//! Specifically, given the enum
27//! ```no_run
28//! use discrimin_ant_proc::discriminant;
29//! #[discriminant(u8)]
30//! pub enum ComplexUEnum {
31//! One(i32) = 1,
32//! Two(i32),
33//! Five { x: u32 } = 5,
34//! Six { x: u32 },
35//! }
36//! ```
37//! the result will be
38//!
39//! ```no_run
40//! #[repr(u8)]
41//! pub enum ComplexUEnum {
42//! One(i32) = 1,
43//! Two(i32),
44//! Five { x: u32 } = 5,
45//! Six { x: u32 },
46//! }
47//! impl ComplexUEnum {
48//! #[doc = r" Returns the discriminant of [Self]."]
49//! pub const fn discriminant(&self) -> u8 {
50//! unsafe { *core::ptr::from_ref::<Self>(self).cast::<u8>() }
51//! }
52//! }
53//! impl discrimin_ant::Discriminantable for ComplexUEnum {
54//! type Discriminant = u8;
55//!
56//! fn discriminant(&self) -> Self::Discriminant {
57//! self.discriminant()
58//! }
59//! }
60//! #[doc = "Fieldless representations of [ComplexUEnum]. Used to extract discriminants without fully constructing the enum."]
61//! #[repr(u8)]
62//! pub enum ComplexUEnum_ {
63//! #[doc = "A fieldless version of [ComplexUEnum::One], used to extract the variant's discriminant without needing to fully construct it."]
64//! One = 1,
65//! #[doc = "A fieldless version of [ComplexUEnum::Two], used to extract the variant's discriminant without needing to fully construct it."]
66//! Two = 1 + 1u8,
67//! #[doc = "A fieldless version of [ComplexUEnum::Five], used to extract the variant's discriminant without needing to fully construct it."]
68//! Five = 5,
69//! #[doc = "A fieldless version of [ComplexUEnum::Six], used to extract the variant's discriminant without needing to fully construct it."]
70//! Six = 5 + 1u8,
71//! }
72//! impl ComplexUEnum_ {
73//! #[doc = r" Returns the discriminant of [Self]."]
74//! pub const fn discriminant(&self) -> u8 {
75//! unsafe { *core::ptr::from_ref::<Self>(self).cast::<u8>() }
76//! }
77//! }
78//! impl discrimin_ant::Discriminantable for ComplexUEnum_ {
79//! type Discriminant = u8;
80//!
81//! fn discriminant(&self) -> Self::Discriminant {
82//! self.discriminant()
83//! }
84//! }
85//! impl TryFrom<u8> for ComplexUEnum_ {
86//! type Error = ();
87//! fn try_from(value: u8) -> Result<Self, Self::Error> {
88//! if value == (1) {
89//! return Ok(Self::One);
90//! }
91//! if value == (1 + 1u8) {
92//! return Ok(Self::Two);
93//! }
94//! if value == (5) {
95//! return Ok(Self::Five);
96//! }
97//! if value == (5 + 1u8) {
98//! return Ok(Self::Six);
99//! }
100//! Err(())
101//! }
102//! }
103//! impl From<&ComplexUEnum> for ComplexUEnum_ {
104//! fn from(value: &ComplexUEnum) -> Self {
105//! match value {
106//! ComplexUEnum::One(..) => Self::One,
107//! ComplexUEnum::Two(..) => Self::Two,
108//! ComplexUEnum::Five { .. } => Self::Five,
109//! ComplexUEnum::Six { .. } => Self::Six,
110//! }
111//! }
112//! }
113//! ```
114//!
115//! Note that the `discriminant` attribute only supports [primitive representations](https://doc.rust-lang.org/reference/type-layout.html#primitive-representations)
116//! since those are the only types that have a [reliably accessible discriminant](https://doc.rust-lang.org/reference/items/enumerations.html#pointer-casting).
117//! Nevertheless, manual implementations of `Discriminant` can be made for any enum (and technically and other object).
118#![no_std]
119
120/// An enum with an accessible discriminant.
121pub trait Discriminantable {
122 /// The type of the discriminant.
123 type Discriminant: num_traits::PrimInt;
124
125 /// Returns the discriminant of the enum.
126 fn discriminant(&self) -> Self::Discriminant;
127}