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;