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}