trait_enum/
lib.rs

1#![deny(missing_docs)]
2#![cfg_attr(not(feature = "std"), no_std)]
3
4//! An enum wrapper for types that implement the same trait
5//!
6//! The `trait_enum` macro generates an `enum` that manages
7//! several objects.
8//!
9//! These objects are expected to have the same trait impl
10//!
11//! After which the enum will have a `std::ops::Deref` impl
12//! which returns a reference to that trait.
13//!
14//! ``` rust
15//! #[macro_use]
16//! extern crate trait_enum;
17//!
18//! pub trait CommonTrait {
19//!     fn test(&self) -> u32;
20//! }
21//!
22//! pub struct InnerOne;
23//! impl CommonTrait for InnerOne {
24//!     fn test(&self) -> u32 {
25//!         1
26//!     }
27//! }
28//!
29//! pub struct InnerTwo;
30//! impl CommonTrait for InnerTwo {
31//!     fn test(&self) -> u32 {
32//!         2
33//!     }
34//! }
35//!
36//! trait_enum!{
37//!     pub enum Combined: CommonTrait {
38//!         InnerOne,
39//!         InnerTwo,
40//!     }
41//! }
42//!
43//! fn main() {
44//!     use std::ops::Deref;
45//!
46//!     let combined = Combined::InnerOne(InnerOne);
47//!     let deref: &CommonTrait = combined.deref();
48//!     assert_eq!(deref.test(), 1);
49//!
50//!     let combined = Combined::InnerTwo(InnerTwo);
51//!     let deref: &CommonTrait = combined.deref();
52//!     assert_eq!(deref.test(), 2);
53//! }
54//! ```
55
56/// An enum wrapper for types that implement the same trait
57///
58/// The `trait_enum` macro generates an `enum` that manages
59/// several objects.
60///
61/// These objects are expected to have the same trait impl
62///
63/// After which the enum will have a `std::ops::Deref` impl
64/// which returns a reference to that trait.
65///
66/// ``` rust
67/// #[macro_use]
68/// extern crate trait_enum;
69///
70/// pub trait CommonTrait {
71///     fn test(&self) -> u32;
72/// }
73///
74/// pub struct InnerOne;
75/// impl CommonTrait for InnerOne {
76///     fn test(&self) -> u32 {
77///         1
78///     }
79/// }
80///
81/// pub struct InnerTwo;
82/// impl CommonTrait for InnerTwo {
83///     fn test(&self) -> u32 {
84///         2
85///     }
86/// }
87///
88/// trait_enum!{
89///     pub enum Combined: CommonTrait {
90///         InnerOne,
91///         InnerTwo,
92///     }
93/// }
94///
95/// fn main() {
96///     use std::ops::Deref;
97///
98///     let combined = Combined::InnerOne(InnerOne);
99///     let deref: &dyn CommonTrait = combined.deref();
100///     assert_eq!(deref.test(), 1);
101///
102///     let combined = Combined::InnerTwo(InnerTwo);
103///     let deref: &dyn CommonTrait = combined.deref();
104///     assert_eq!(deref.test(), 2);
105/// }
106/// ```
107#[macro_export]
108macro_rules! trait_enum {
109    (
110        $(#[$outer:meta])*
111        pub enum $EnumName:ident: $Trait:tt {
112            $(
113                $(#[$inner:meta])*
114                $name:ident,
115            )+
116        }
117    ) => {
118        $crate::__trait_enum! {
119            $(#[$outer])*
120            (pub) $EnumName: $Trait {
121                $(
122                $(#[$inner])*
123                    $name,
124                )+
125            }
126        }
127    };
128    (
129        $(#[$outer:meta])*
130        enum $EnumName:ident: $Trait:tt {
131            $(
132                $(#[$inner:meta])*
133                $name:ident,
134            )+
135        }
136    ) => {
137        $crate::__trait_enum! {
138            $(#[$outer])*
139            () $EnumName: $Trait {
140                $(
141                $(#[$inner])*
142                    $name,
143                )+
144            }
145        }
146    };
147
148    (
149        $(#[$outer:meta])*
150        pub enum $EnumName:ident: $Trait:tt {
151            $(
152                $(#[$inner:meta])*
153                $name:ident
154            ),+
155        }
156    ) => {
157        $crate::__trait_enum! {
158            $(#[$outer])*
159            (pub) $EnumName: $Trait {
160                $(
161                    $(#[$inner])*
162                    $name,
163                )+
164            }
165        }
166    };
167    (
168        $(#[$outer:meta])*
169        enum $EnumName:ident: $Trait:tt {
170            $(
171                $(#[$inner:meta])*
172                $name:ident
173            ),+
174        }
175    ) => {
176        $crate::__trait_enum! {
177            $(#[$outer])*
178            () $EnumName: $Trait {
179                $(
180                    $(#[$inner])*
181                    $name,
182                )+
183            }
184        }
185    };
186    (
187        $(#[$outer:meta])*
188        pub ($($vis:tt)+) struct $EnumName:ident: $Trait:tt {
189            $(
190                $(#[$inner:meta])*
191                $name:ident
192            ),+
193        }
194    ) => {
195        $crate::__trait_enum! {
196            $(#[$outer])*
197            (pub ($($vis)+)) $EnumName: $Trait {
198                $(
199                $(#[$inner:meta])*
200                    $name,
201                )+
202            }
203        }
204    };
205}
206
207#[macro_export]
208#[doc(hidden)]
209macro_rules! __trait_enum {
210    (
211        $(#[$outer:meta])*
212        ($($vis:tt)*) $EnumName:ident: $Trait:tt {
213            $(
214                $(#[$inner:meta])*
215                $name:ident,
216            )+
217        }
218    ) => {
219        $(#[$outer])*
220        $($vis)* enum $EnumName {
221            $(
222                $(#[$inner])*
223                $name($name),
224            )*
225        }
226
227        impl $crate::Deref for $EnumName {
228            type Target = dyn $Trait;
229
230            fn deref(&self) -> &(dyn $Trait + 'static) {
231                match self {
232                    $(
233                        $EnumName::$name(v) => v as &dyn $Trait,
234                    )*
235                }
236            }
237        }
238
239        impl $crate::DerefMut for $EnumName {
240            fn deref_mut(&mut self) -> &mut (dyn $Trait + 'static) {
241                match self {
242                    $(
243                        $EnumName::$name(v) => v as &mut dyn $Trait,
244                    )*
245                }
246            }
247        }
248    };
249}
250
251#[cfg(not(feature = "std"))]
252pub use core::ops::{Deref, DerefMut};
253#[cfg(feature = "std")]
254pub use std::ops::{Deref, DerefMut};
255
256#[cfg(test)]
257pub mod test;