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}