enum_to_types/lib.rs
1//! Macro for generating pseudo-enums for type-level programming.
2//! This is somewhat like https://github.com/fmease/tylift but implemented with `macro_rules!` syntax
3//! ```
4//! # use enum_to_types::enum_to_types;
5//! # use std::marker::PhantomData;
6//! enum_to_types!(AccessLevel; User, Admin);
7//!
8//! struct DataStorage<T: AccessLevel::AccessLevel>(i32, PhantomData<T>);
9//!
10//! impl<T: AccessLevel::AccessLevel> DataStorage<T> {
11//! fn new(i: i32) -> Self {
12//! Self(i, PhantomData)
13//! }
14//! }
15//!
16//! trait ReadStorage<T: AccessLevel::AccessLevel> {
17//! fn read(&self) -> i32;
18//! }
19//!
20//! impl ReadStorage<AccessLevel::Admin> for DataStorage<AccessLevel::User> {
21//! fn read(&self) -> i32 {
22//! self.0
23//! }
24//! }
25//!
26//! impl ReadStorage<AccessLevel::User> for DataStorage<AccessLevel::User> {
27//! fn read(&self) -> i32 {
28//! self.0
29//! }
30//! }
31//!
32//! impl ReadStorage<AccessLevel::Admin> for DataStorage<AccessLevel::Admin> {
33//! fn read(&self) -> i32 {
34//! self.0
35//! }
36//! }
37//!
38//! impl ReadStorage<AccessLevel::User> for DataStorage<AccessLevel::Admin> {
39//! fn read(&self) -> i32 {
40//! panic!("You have no rights to read this");
41//! }
42//! }
43//!
44//! fn main() {
45//! let storage = DataStorage::<AccessLevel::Admin>::new(1);
46//! assert_eq!(<DataStorage::<AccessLevel::Admin> as ReadStorage<AccessLevel::Admin>>::read(&storage), 1);
47//! let storage = DataStorage::<AccessLevel::User>::new(5);
48//! assert_eq!(<DataStorage::<AccessLevel::User> as ReadStorage<AccessLevel::User>>::read(&storage), 5);
49//! // reading storage with `AccessLevel::Admin` by user will cause panic
50//! }
51//! ```
52//! This may look very verbose but it gives a lot of flexibility.
53//! Also, other examples can look less verbose.
54
55/// Macro for generating pseudo-enums for type-level programming.
56/// This is somewhat like https://github.com/fmease/tylift but implemented with `macro_rules!` syntax
57/// ```
58/// # use enum_to_types::enum_to_types;
59/// # use std::marker::PhantomData;
60/// enum_to_types!(AccessLevel; User, Admin);
61///
62/// struct DataStorage<T: AccessLevel::AccessLevel>(i32, PhantomData<T>);
63///
64/// impl<T: AccessLevel::AccessLevel> DataStorage<T> {
65/// fn new(i: i32) -> Self {
66/// Self(i, PhantomData)
67/// }
68/// }
69///
70/// trait ReadStorage<T: AccessLevel::AccessLevel> {
71/// fn read(&self) -> i32;
72/// }
73///
74/// impl ReadStorage<AccessLevel::Admin> for DataStorage<AccessLevel::User> {
75/// fn read(&self) -> i32 {
76/// self.0
77/// }
78/// }
79///
80/// impl ReadStorage<AccessLevel::User> for DataStorage<AccessLevel::User> {
81/// fn read(&self) -> i32 {
82/// self.0
83/// }
84/// }
85///
86/// impl ReadStorage<AccessLevel::Admin> for DataStorage<AccessLevel::Admin> {
87/// fn read(&self) -> i32 {
88/// self.0
89/// }
90/// }
91///
92/// impl ReadStorage<AccessLevel::User> for DataStorage<AccessLevel::Admin> {
93/// fn read(&self) -> i32 {
94/// panic!("You have no rights to read this");
95/// }
96/// }
97///
98/// fn main() {
99/// let storage = DataStorage::<AccessLevel::Admin>::new(1);
100/// assert_eq!(<DataStorage::<AccessLevel::Admin> as ReadStorage<AccessLevel::Admin>>::read(&storage), 1);
101/// let storage = DataStorage::<AccessLevel::User>::new(5);
102/// assert_eq!(<DataStorage::<AccessLevel::User> as ReadStorage<AccessLevel::User>>::read(&storage), 5);
103/// // reading storage with `AccessLevel::Admin` by user will cause panic
104/// }
105/// ```
106/// This may look very verbose but it gives a lot of flexibility.
107/// Also, other examples can look less verbose.
108#[macro_export]
109macro_rules! enum_to_types {
110 ($name:ident; $($variant:ident),+) => {
111 pub mod $name {
112 pub trait $name {}
113 $(
114 #[derive(Debug, Ord, Hash, Eq, PartialOrd, PartialEq)]
115 pub struct $variant;
116 impl $name for $variant {}
117 )+
118 }
119 };
120}