[go: up one dir, main page]

conv/
macros.rs

1/*!
2This module provides convenience macros to help with implementing the conversion traits.
3
4# `TryFrom!`
5
6```ignore
7macro_rules! TryFrom {
8    (($target:ty) $enum:item) => { ... };
9}
10```
11
12This macro attempts to derive an implementation of the [`TryFrom`](../trait.TryFrom.html) trait.  Specifically, it supports `enum`s consisting entirely of unitary variants, with or without explicit values.  The source type can be any integer type which the variants of the enumeration can be explicitly cast to (*i.e.* using `as`).
13
14If a conversion fails (due to there being no matching variant for the specified integer value `src`), then the conversion returns `Err(Unrepresentable(src))` (see [`Unrepresentable`](../errors/struct.Unrepresentable.html)).
15
16It is compatible with the [`custom_derive!`](https://crates.io/crates/custom_derive) macro.
17
18## Example
19
20Using `custom_derive!`:
21
22```
23#[macro_use] extern crate conv;
24#[macro_use] extern crate custom_derive;
25
26custom_derive! {
27    #[derive(Debug, PartialEq, TryFrom(i32))]
28    enum Colours {
29        Red = 0,
30        Green = 5,
31        Blue
32    }
33}
34
35fn main() {
36    use conv::{TryFrom, Unrepresentable};
37
38    assert_eq!(Colours::try_from(0), Ok(Colours::Red));
39    assert_eq!(Colours::try_from(1), Err(Unrepresentable(1)));
40    assert_eq!(Colours::try_from(5), Ok(Colours::Green));
41    assert_eq!(Colours::try_from(6), Ok(Colours::Blue));
42    assert_eq!(Colours::try_from(7), Err(Unrepresentable(7)));
43}
44```
45
46The above is equivalent to the following:
47
48```
49#[macro_use] extern crate conv;
50
51#[derive(Debug, PartialEq)]
52enum Colours {
53    Red = 0,
54    Green = 5,
55    Blue
56}
57
58TryFrom! { (i32) enum Colours {
59    Red = 0,
60    Green = 5,
61    Blue
62} }
63# fn main() {}
64```
65*/
66
67/**
68See the documentation for the [`macros`](./macros/index.html#tryfrom!) module for details.
69*/
70#[macro_export]
71macro_rules! TryFrom {
72    (($prim:ty) $(pub)* enum $name:ident { $($body:tt)* }) => {
73        TryFrom! {
74            @collect_variants ($name, $prim),
75            ($($body)*,) -> ()
76        }
77    };
78
79    (
80        @collect_variants ($name:ident, $prim:ty),
81        ($(,)*) -> ($($var_names:ident,)*)
82    ) => {
83        impl $crate::TryFrom<$prim> for $name {
84            type Err = $crate::errors::Unrepresentable<$prim>;
85            fn try_from(src: $prim) -> Result<$name, Self::Err> {
86                $(
87                    if src == $name::$var_names as $prim {
88                        return Ok($name::$var_names);
89                    }
90                )*
91                Err($crate::errors::Unrepresentable(src))
92            }
93        }
94    };
95
96    (
97        @collect_variants $fixed:tt,
98        (#[$_attr:meta] $($tail:tt)*) -> $var_names:tt
99    ) => {
100        TryFrom! {
101            @skip_meta $fixed,
102            ($($tail)*) -> $var_names
103        }
104    };
105
106    (
107        @collect_variants $fixed:tt,
108        ($var:ident $(= $_val:expr)*, $($tail:tt)*) -> ($($var_names:tt)*)
109    ) => {
110        TryFrom! {
111            @collect_variants $fixed,
112            ($($tail)*) -> ($($var_names)* $var,)
113        }
114    };
115
116    (
117        @collect_variants ($name:ident),
118        ($var:ident $_struct:tt, $($tail:tt)*) -> ($($var_names:tt)*)
119    ) => {
120        const _error: () = concat!(
121            "cannot derive TryFrom for ",
122            stringify!($name),
123            ", due to non-unitary variant ",
124            stringify!($var),
125            "."
126        );
127    };
128    
129    (
130        @skip_meta $fixed:tt,
131        (#[$_attr:meta] $($tail:tt)*) -> $var_names:tt
132    ) => {
133        TryFrom! {
134            @skip_meta $fixed,
135            ($($tail)*) -> $var_names
136        }
137    };
138
139    (
140        @skip_meta $fixed:tt,
141        ($var:ident $($tail:tt)*) -> $var_names:tt
142    ) => {
143        TryFrom! {
144            @collect_variants $fixed,
145            ($var $($tail)*) -> $var_names
146        }
147    };
148}