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}