boolean_enums/
lib.rs

1// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
3// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
4// option. This file may not be copied, modified, or distributed
5// except according to those terms.
6
7#![warn(bare_trait_objects)]
8#![warn(clippy::pedantic)]
9
10#![cfg_attr(not(feature = "std"), no_std)]
11
12//! Generate your Yes/No enum with `gen_boolean_enum!`:
13//! ```
14//! # #[macro_use] extern crate boolean_enums;
15//! #
16//! gen_boolean_enum!(MyEnum);
17//! ```
18//!
19//! It's From<bool> and Into<bool> and Not:
20//! ```
21//! # #[macro_use] extern crate boolean_enums;
22//! #
23//! # gen_boolean_enum!(MyEnum);
24//! #
25//! let flag = MyEnum::Yes;
26//! let oflag = true.into();
27//! assert_eq!(flag, oflag);
28//!
29//! if (!flag).into() {
30//!     unreachable!()
31//! }
32//! ```
33//!
34//! To generate a public enum, you need to append `pub` to
35//! the macro arguments:
36//! ```
37//! # #[macro_use] extern crate boolean_enums;
38//! #
39//! gen_boolean_enum!(pub MyEnum);
40//! ```
41//!
42//! You can serialize and deserialize it with serde like a normal bool
43//! (enabled by the `serde` feature).  For that, specify `serde`
44//! before the enum name in `gen_boolean_enum!`:
45//! ```rust
46//! #[macro_use] extern crate boolean_enums;
47//!
48//! # #[cfg(feature = "serde")]
49//! # {
50//! extern crate toml; // as an example serde format
51//!
52//! gen_boolean_enum!(serde MyEnum);
53//! // or gen_boolean_enum!(pub serde MyEnum);
54//!
55//! #[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
56//! struct SomeStruct {
57//!     flag: MyEnum
58//! }
59//!
60//! // …
61//!
62//! let first = SomeStruct {
63//!     flag: MyEnum::Yes
64//! };
65//! let string = toml::ser::to_string(&first).unwrap();
66//! let second: SomeStruct = toml::de::from_str(&string).unwrap();
67//!
68//! assert_eq!(first, second);
69//! # }
70//! ```
71//!
72//! You can use boolean-enums in `no_std` crates by disabling the default `std`
73//! feature:
74//! ```toml,ignore
75//! [dependencies.boolean-enums]
76//! version = "^0.3.0"
77//! default-features = false
78//! ```
79//!
80//! # Examples
81//! ```
82//! #[macro_use] extern crate boolean_enums;
83//!
84//! gen_boolean_enum!(First);
85//! gen_boolean_enum!(Second);
86//! gen_boolean_enum!(Third);
87//!
88//! fn do_smth(flag1: First, flag2: Second, flag3: Third) {
89//!     // …
90//! }
91//!
92//! let first = First::Yes;
93//! let second = Second::No;
94//! let third = Third::Yes;
95//!
96//! do_smth(first, second, third);
97//! ```
98//! That compiles perfectly, but
99//! ```rust,compile_fail
100//! # #[macro_use] extern crate boolean_enums;
101//! #
102//! # gen_boolean_enum!(First);
103//! # gen_boolean_enum!(Second);
104//! # gen_boolean_enum!(Third);
105//! #
106//! # fn do_smth(flag1: First, flag2: Second, flag3: Third) {
107//! #     // …
108//! # }
109//! #
110//! # let first = First::Yes;
111//! # let second = Second::No;
112//! # let third = Third::Yes;
113//! #
114//! do_smth(first, third, second);
115//! ```
116//! fails to compile.
117
118#[cfg(feature = "serde")]
119extern crate serde;
120
121#[cfg(feature = "std")]
122#[doc(hidden)]
123pub mod lstd {
124    pub use std::*;
125}
126
127#[cfg(not(feature = "std"))]
128#[doc(hidden)]
129pub mod lstd {
130    pub use core::*;
131}
132
133#[cfg(feature = "serde")]
134#[doc(hidden)]
135pub use serde::*;
136
137/// Generates enum with Yes and No variants.
138///
139/// # Examples
140///
141/// ```
142/// # #[macro_use] extern crate boolean_enums;
143/// #
144/// gen_boolean_enum!(DoX);
145///
146/// // …
147///
148/// # fn main() {
149/// let flag = DoX::Yes;
150/// let mut other_flag = DoX::No;
151///
152/// if flag.into() {
153///     other_flag = true.into();
154/// }
155///
156/// assert_eq!(other_flag, DoX::Yes);
157/// # }
158/// ```
159#[macro_export]
160macro_rules! gen_boolean_enum {
161    ($name:ident) => (
162        _gen_boolean_enum_gen_enum!($name);
163        _gen_boolean_enum_common!($name);
164    );
165
166    (pub $name:ident) => (
167        _gen_boolean_enum_gen_enum!(pub $name);
168        _gen_boolean_enum_common!($name);
169    );
170
171    (serde $name:ident) => (
172        _gen_boolean_enum_gen_enum!($name);
173        _gen_boolean_enum_common!($name);
174        _gen_boolean_enum_serde!($name);
175    );
176
177    (pub serde $name:ident) => (
178        _gen_boolean_enum_gen_enum!(pub $name);
179        _gen_boolean_enum_common!($name);
180        _gen_boolean_enum_serde!($name);
181    );
182
183    (serde pub $name:ident) => (
184        gen_boolean_enum!(pub serde $name);
185    )
186}
187
188#[doc(hidden)]
189#[macro_export]
190macro_rules! _gen_boolean_enum_common {
191    ($name:ident) => (
192        impl From<bool> for $name {
193            fn from(x: bool) -> Self {
194                if x {
195                    $name::Yes
196                } else {
197                    $name::No
198                }
199            }
200        }
201
202        impl Into<bool> for $name {
203            fn into(self) -> bool {
204                match self {
205                    $name::Yes => true,
206                    $name::No => false
207                }
208            }
209        }
210
211        impl Default for $name {
212            fn default() -> Self {
213                $name::No
214            }
215        }
216
217        impl $crate::lstd::ops::Not for $name {
218            type Output = Self;
219            fn not(self) -> Self::Output {
220                if self.into() {
221                    $name::No
222                } else {
223                    $name::Yes
224                }
225            }
226        }
227    )
228}
229
230#[doc(hidden)]
231#[macro_export]
232macro_rules! _gen_boolean_enum_gen_enum {
233    ($name:ident) => (
234        #[derive(Clone, Copy, Debug, Eq, PartialEq)]
235        enum $name {
236            Yes,
237            No
238        }
239    );
240    (pub $name:ident) => (
241        #[derive(Clone, Copy, Debug, Eq, PartialEq)]
242        pub enum $name {
243            Yes,
244            No
245        }
246    );
247}
248
249#[cfg(not(feature = "serde"))]
250#[doc(hidden)]
251#[macro_export]
252macro_rules! _gen_boolean_enum_serde {
253    ( $( $t:tt )* ) => (
254        compile_error!("the \"serde\" feature is not enabled");
255    )
256}
257
258#[cfg(feature = "serde")]
259#[doc(hidden)]
260#[macro_export]
261macro_rules! _gen_boolean_enum_serde {
262    ($name:ident) => (
263        impl $crate::Serialize for $name {
264            fn serialize<S>(
265                &self,
266                serializer: S
267            ) -> $crate::lstd::result::Result<S::Ok, S::Error>
268            where S: $crate::Serializer {
269                serializer.serialize_bool((*self).into())
270            }
271        }
272
273        impl<'de> $crate::Deserialize<'de> for $name {
274            fn deserialize<D>(
275                deserializer: D
276            ) -> $crate::lstd::result::Result<$name, D::Error>
277            where D: $crate::Deserializer<'de> {
278                struct BooleanEnumVisitor;
279
280                impl<'de> $crate::de::Visitor<'de>
281                        for BooleanEnumVisitor {
282                    type Value = $name;
283
284                    fn expecting(
285                        &self,
286                        formatter: &mut $crate::lstd::fmt::Formatter
287                    ) -> $crate::lstd::fmt::Result {
288                        formatter.write_str("a boolean value")
289                    }
290
291                    fn visit_bool<E>(
292                        self,
293                        value: bool
294                    ) -> $crate::lstd::result::Result<Self::Value, E>
295                    where E: $crate::de::Error {
296                        Ok($name::from(value))
297                    }
298                }
299
300                deserializer.deserialize_bool(BooleanEnumVisitor)
301            }
302        }
303    )
304}