enumx/
lib.rs

1// See the COPYRIGHT file at the top-level directory of this distribution.
2// Licensed under MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>
3
4//! enumx = ENUM eXtensions.
5//!
6//! See the [enumx book](https://oooutlk.github.io/enumx/) for more.
7
8#![cfg_attr( feature="unstable", feature(
9    fn_traits,
10    generator_trait,
11    generators,
12    trusted_len,
13    unboxed_closures
14))]
15
16#[macro_use]
17pub mod macros;
18
19/// Reorganize types, traits and macros to export to end users.
20///
21/// Two categories:
22///
23/// 1. enum exchange.
24///
25/// 2. enum trait implementations.
26///
27/// If users want to import utils in #1, just `use enumx::export::exchange::*;`.
28/// If users want to import utils in #2, just `use enumx::export::impls::*;`.
29/// If utils both in #1 and #2 are needed, just `use enumx::export::*;`.
30pub mod export {
31    pub mod exchange {
32        pub use crate::{
33            EnumToEnum,
34            ExchangeFrom,
35            ExchangeInto,
36            FromVariant,
37            IntoEnum,
38            TyPat,
39        };
40        pub use enumx_derive::{
41            Enum,
42            Exchange,
43            FromVariant as _,
44            Proto,
45            def_impls,
46            enumx,
47        };
48    }
49    pub mod impls {
50        pub mod derives {
51            pub use enumx_derive::{
52                def_impls,
53                sum,
54                sum_err,
55            };
56        }
57        pub use derives::*;
58        pub use crate::{
59            impl_trait,
60            impl_super_traits,
61            impl_all_traits,
62        };
63    }
64
65    pub use exchange::*;
66    pub use impls::*;
67}
68
69pub use enumx_derive::{
70    Enum,
71    Exchange,
72    FromVariant,
73    Proto,
74    def_impls,
75    enumx,
76    sum,
77    sum_err,
78};
79
80/// Constructs an enum from one of its variants.
81pub trait FromVariant<Variant, Index> {
82    fn from_variant( variant: Variant ) -> Self;
83}
84
85/// Wraps a variant into an enum.
86pub trait IntoEnum<Enum, Index> {
87    fn into_enum( self ) -> Enum;
88}
89
90impl<Enum,Variant,Index> IntoEnum<Enum, Index> for Variant
91    where Enum: FromVariant<Variant, Index>
92{
93    fn into_enum( self ) -> Enum {
94        <Enum as FromVariant::<Variant, Index>>::from_variant( self )
95    }
96}
97
98/// Constructs an enum from one of its variants, or from an enum composed of a subset of its variants.
99pub trait ExchangeFrom<Src, Index> {
100    fn exchange_from( src: Src ) -> Self;
101}
102
103/// Wraps a variant into an enum, or converts an enum into another one, the variants of which is a superset of the converted enum's.
104pub trait ExchangeInto<Dest, Index> {
105    fn exchange_into( self ) -> Dest;
106}
107
108impl<Src, Dest, Index> ExchangeInto<Dest, Index> for Src
109    where Dest: ExchangeFrom<Src, Index>,
110{
111    fn exchange_into( self ) -> Dest {
112        Dest::exchange_from( self )
113    }
114}
115
116/// Used in `ExchangeFrom`/`ExchangeInto` to distinguish conversions between enums from those between an enum and its variant.
117pub struct EnumToEnum<Index>( Index );
118
119/// Indicates the prototype for a user-defined `Exchange`-able enum.
120pub trait Proto {
121    type Type;
122    fn from_proto( src: Self::Type ) -> Self;
123    fn into_proto( self ) -> Self::Type;
124}
125
126/// # Predefined ad-hoc enums
127///
128/// This library has defined `Enum0`, `Enum1` .. up to `Enum16` by default.
129///
130/// The library user can `use enumx::predefined::*;` for convenience.
131///
132/// A feature named "enum32" increases the set of predefined enums up to `Enum32`.
133///
134/// `Cargo.toml`:
135///
136/// ```toml
137/// [dependencies.enumx]
138/// version = "0.4"
139/// features = "enum32"
140/// ```
141///
142/// The predefined enums can be disabled by opting out "Enum16" and "Enum32" features.
143///
144/// `Cargo.toml`:
145///
146/// ```toml
147/// [dependencies.enumx]
148/// version = "0.4"
149/// default-features = false
150/// ```
151#[cfg( any( feature="enum16", feature="enum32" ))]
152pub mod predefined {
153    use crate as enumx;
154    use crate::{Exchange, def_impls, impl_trait};
155
156    #[cfg( feature="enum16" )]
157    def_impls! {
158        #[derive( Exchange, Clone, Debug, PartialEq, Eq, PartialOrd, Ord )]
159        pub enum Enum![ 0..=16 ];
160    }
161
162    #[cfg( feature="enum32" )]
163    def_impls! {
164        #[derive( Exchange, Clone, Debug, PartialEq, Eq, PartialOrd, Ord )]
165        pub enum Enum![ 17..=32 ];
166    }
167
168    #[cfg( feature="enum16" )]
169    pub mod enum1_16 {
170        use super::*;
171
172        impl_trait!{ _impl!(T) AsRef<T> _for!( Enum![1..=16] )}
173        impl_trait!{ _impl!(T) AsMut<T> _for!( Enum![1..=16] )}
174        impl_trait!{ DoubleEndedIterator _for!( Enum![1..=16] )}
175        impl_trait!{ ExactSizeIterator _for!( Enum![1..=16] )}
176        impl_trait!{ _impl!(A) Extend<A> _for!( Enum![1..=16] )}
177        impl_trait!{ Iterator _for!( Enum![1..=16] )}
178        impl_trait!{ std::error::Error _for!( Enum![1..=16] )}
179        impl_trait!{ std::fmt::Display _for!( Enum![1..=16] )}
180        impl_trait!{ std::iter::FusedIterator _for!( Enum![1..=16] )}
181        impl_trait!{ std::ops::Deref _for!( Enum![1..=16] )}
182        impl_trait!{ std::ops::DerefMut _for!( Enum![1..=16] )}
183
184        #[cfg( feature="unstable" )]
185        crate::impl_all_traits!{ _impl!(Args) Fn<Args> _for!( Enum![1..=16] )}
186
187        #[cfg( feature="unstable" )]
188        impl_trait!{ std::iter::TrustedLen _for!( Enum![1..=16] )}
189
190        #[cfg( feature="unstable" )]
191        impl_trait!{ _impl!(R) std::ops::Generator<R> _for!( Enum![1..=16] )}
192    }
193
194    #[cfg( feature="enum32" )]
195    pub mod enum17_32 {
196        use super::*;
197
198        impl_trait!{ _impl!(T) AsRef<T> _for!( Enum![17..=32] )}
199        impl_trait!{ _impl!(T) AsMut<T> _for!( Enum![17..=32] )}
200        impl_trait!{ DoubleEndedIterator _for!( Enum![17..=32] )}
201        impl_trait!{ ExactSizeIterator _for!( Enum![17..=32] )}
202        impl_trait!{ _impl!(A) Extend<A> _for!( Enum![17..=32] )}
203        impl_trait!{ Iterator _for!( Enum![17..=32] )}
204        impl_trait!{ std::error::Error _for!( Enum![17..=32] )}
205        impl_trait!{ std::fmt::Display _for!( Enum![17..=32] )}
206        impl_trait!{ std::iter::FusedIterator _for!( Enum![17..=32] )}
207        impl_trait!{ std::ops::Deref _for!( Enum![17..=32] )}
208        impl_trait!{ std::ops::DerefMut _for!( Enum![17..=32] )}
209
210        #[cfg( feature="unstable" )]
211        crate::impl_all_traits!{ _impl!(Args) Fn<Args> _for!( Enum![17..=32] )}
212
213        #[cfg( feature="unstable" )]
214        impl_trait!{ std::iter::TrustedLen _for!( Enum![17..=32] )}
215
216        #[cfg( feature="unstable" )]
217        impl_trait!{ _impl!(R) std::ops::Generator<R> _for!( Enum![17..=32] )}
218    }
219}
220
221/// Since `enum`s in Rust do not have prototypes, this mod does the work.
222pub mod proto {
223    use crate as enumx;
224    use crate::def_impls;
225
226    def_impls! {
227        pub enum __![ 0..=16 ];
228    }
229
230    #[cfg( feature="enum32" )]
231    def_impls! {
232        pub enum __![ 17..=32 ];
233    }
234}
235
236macro_rules! impl_exchange_from {
237    ( $($index:tt)+ ) => {
238        $(
239            impl<Enum,Variant> ExchangeFrom<Variant,[(); $index]> for Enum
240                where Enum: FromVariant<Variant,[(); $index]>
241            {
242                fn exchange_from( variant: Variant ) -> Self {
243                    Enum::from_variant( variant )
244                }
245            }
246        )+
247    };
248}
249
250impl_exchange_from!( 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 );
251
252/// Wrapper for non-path types in type pattern matching using `#[ty_pat]` match
253/// ```rust,no_run
254/// use enumx::export::*;
255/// use enumx::predefined::*;
256///
257/// #[enumx] fn bar( input: Enum!(&'static str,i32) ) {
258///     #[ty_pat] match input {
259///         TyPat::<&'static str>(s) => println!( "it's static str:{}", s ),
260///         i32(i) => println!( "it's i32:{}", i ),
261///     }
262/// }
263/// ```
264pub type TyPat<T> = T;
265
266#[cfg( test )]
267mod tests {
268    mod test_unnamed {
269        use crate::*;
270        use crate::predefined::*;
271
272        #[test]
273        fn test_from_variant() {
274            let enum1 = Enum1::<i32>::from_variant( 2018 );
275            assert_eq!( enum1, Enum1::_0( 2018 ));
276
277            let enum2 = Enum2::<i32, String>::from_variant( "rust".to_string() );
278            assert_eq!( enum2, Enum2::_1( "rust".to_string() ));
279
280            let enum3 = Enum3::<i32, String, bool>::from_variant( true );
281            assert_eq!( enum3, Enum3::_2( true ));
282        }
283
284        #[test]
285        fn test_into_enum() {
286            let enum1: Enum1<i32> = 2018.exchange_into();
287            assert_eq!( enum1, Enum1::_0( 2018 ));
288
289            let enum2: Enum2<i32, String> = "rust".to_string().exchange_into();
290            assert_eq!( enum2, Enum2::_1( "rust".to_string() ));
291
292            let enum3: Enum3<i32, String, bool> = true.exchange_into();
293            assert_eq!( enum3, Enum3::_2( true ));
294        }
295
296        #[test]
297        fn test_exchange_from() {
298            let enum1 = Enum1::<String>::exchange_from( "rust".to_string() );
299
300            let enum1 = Enum1::<String>::exchange_from( enum1 );
301            assert_eq!( enum1, Enum1::_0( "rust".to_string() ));
302
303            let enum2 = Enum2::<i32, String>::exchange_from( enum1 );
304            assert_eq!( enum2, Enum2::_1( "rust".to_string() ));
305
306            let enum2 = Enum2::<String, i32>::exchange_from( enum2 );
307            assert_eq!( enum2, Enum2::_0("rust".to_string() ));
308
309            let enum3 = Enum3::<bool, i32, String>::exchange_from( enum2 );
310            assert_eq!( enum3, Enum3::_2( "rust".to_string() ));
311
312            let enum3 = Enum3::<String, i32, bool>::exchange_from( enum3 );
313            assert_eq!( enum3, Enum3::_0( "rust".to_string() ));
314        }
315
316        #[test]
317        fn test_exchange_into() {
318            let enum1 = Enum1::<i32>::exchange_from( 2018 );
319
320            let enum1: Enum1<i32> = enum1.exchange_into();
321            assert_eq!( enum1, Enum1::_0( 2018 ));
322
323            let enum2: Enum2<String, i32> = enum1.exchange_into();
324            assert_eq!( enum2, Enum2::_1( 2018 ));
325
326            let enum2: Enum2<i32, String> = enum2.exchange_into();
327            assert_eq!( enum2, Enum2::_0( 2018 ));
328
329            let enum3: Enum3<bool, String, i32> = enum2.exchange_into();
330            assert_eq!( enum3, Enum3::_2( 2018 ));
331
332            let enum3: Enum3<i32, String, bool> = enum3.exchange_into();
333            assert_eq!( enum3, Enum3::_0( 2018 ));
334        }
335    }
336
337    mod test_named {
338        use crate::*;
339        use crate::predefined::*;
340        use crate as enumx;
341
342        #[derive( Exchange, Clone, Debug, PartialEq, Eq, PartialOrd, Ord )]
343        enum One<T> {
344            The(T),
345        }
346
347        #[derive( Exchange, Clone, Debug, PartialEq, Eq, PartialOrd, Ord )]
348        enum Two<A, B> {
349            Former(A),
350            Latter(B),
351        }
352
353        #[derive( Exchange, Clone, Debug, PartialEq, Eq, PartialOrd, Ord )]
354        enum Three<A, B, C> {
355            First(A),
356            Second(B),
357            Third(C),
358        }
359
360        #[test]
361        fn test_from_variant() {
362            let one = One::<i32>::from_variant( 2018 );
363            assert_eq!( one, One::The( 2018 ));
364
365            let two = Two::<i32, String>::from_variant( "rust".to_string() );
366            assert_eq!( two, Two::Latter( "rust".to_string() ));
367
368            let three = Three::<i32, String, bool>::from_variant( true );
369            assert_eq!( three, Three::Third( true ));
370        }
371
372        #[test]
373        fn test_into_enum() {
374            let one: One<i32> = 2018.into_enum();
375            assert_eq!( one, One::The( 2018 ));
376
377            let two: Two<i32, String> = "rust".to_string().into_enum();
378            assert_eq!( two, Two::Latter( "rust".to_string() ));
379
380            let three: Three<i32, String, bool> = true.into_enum();
381            assert_eq!( three, Three::Third( true ));
382        }
383
384        #[test]
385        fn test_exchange_from() {
386            let one = One::<i32>::exchange_from( 2018 );
387            let enum1 = Enum1::<i32>::exchange_from( one );
388            let one = One::<i32>::exchange_from( enum1 );
389
390            let one = One::<i32>::exchange_from( one );
391            assert_eq!( one, One::The( 2018 ));
392
393            let two = Two::<String, i32>::exchange_from( one );
394            assert_eq!( two, Two::Latter( 2018 ));
395
396            let two = Two::<i32, String>::exchange_from( two );
397            assert_eq!( two, Two::Former( 2018 ));
398
399            let three = Three::<bool, String, i32>::exchange_from( two );
400            assert_eq!( three, Three::Third( 2018 ));
401
402            let three = Three::<i32, String, bool>::exchange_from( three );
403            assert_eq!( three, Three::First( 2018 ));
404        }
405
406        #[test]
407        fn test_exchange_into() {
408            let one = One::<String>::exchange_from( "rust".to_string() );
409
410            let one: One<String> = one.exchange_into();
411            assert_eq!( one, One::The( "rust".to_string() ));
412
413            let two: Two<i32, String> = one.exchange_into();
414            assert_eq!( two, Two::Latter( "rust".to_string() ));
415
416            let two: Two<String, i32> = two.exchange_into();
417            assert_eq!( two, Two::Former( "rust".to_string() ));
418
419            let three: Three<bool, i32, String> = two.exchange_into();
420            assert_eq!( three, Three::Third( "rust".to_string() ));
421
422            let three: Three<String, i32, bool> = three.exchange_into();
423            assert_eq!( three, Three::First( "rust".to_string() ));
424        }
425
426        #[test]
427        fn test_adhoc_from_named() {
428            let three = Three::<bool, String, i32>::exchange_from( 2018 );
429            let enum3 = Enum3::<String, i32, bool>::exchange_from( three );
430            assert_eq!( enum3, Enum3::_1( 2018 ));
431        }
432
433        #[test]
434        fn test_adhoc_into_named() {
435            let enum3 = Enum3::<String, i32, bool>::exchange_from( 2018 );
436            let three: Three<bool, String, i32> = enum3.exchange_into();
437            assert_eq!( three, Three::Third( 2018 ));
438        }
439
440        #[test]
441        fn test_named_into_adhoc() {
442            let three = Three::<bool, String, i32>::exchange_from( 2018 );
443            let enum3: Enum3<String, i32, bool> = three.exchange_into();
444            assert_eq!( enum3, Enum3::_1( 2018 ));
445        }
446
447        #[test]
448        fn test_named_from_adhoc() {
449            let enum3 = Enum3::<String, i32, bool>::exchange_from( 2018 );
450            let three = Three::<bool, String, i32>::exchange_from( enum3 );
451            assert_eq!( three, Three::Third( 2018 ));
452        }
453    }
454}