boolinator/
lib.rs

1/*
2Copyright ⓒ 2016 Daniel Keep.
3
4Licensed under the MIT license (see LICENSE or <http://opensource.org
5/licenses/MIT>) or the Apache License, Version 2.0 (see LICENSE of
6<http://www.apache.org/licenses/LICENSE-2.0>), at your option. All
7files in the project carrying such notice may not be copied, modified,
8or distributed except according to those terms.
9*/
10/*!
11
12Provides the [`Boolinator`](trait.Boolinator.html) trait, which lets you use `Option` and `Result`-style combinators with `bool`s.
13
14<style type="text/css">
15.link-block { font-family: "Fira Sans"; }
16.link-block > p { display: inline-block; }
17.link-block > p > strong { font-weight: 500; margin-right: 1em; }
18.link-block > ul { display: inline-block; padding: 0; list-style: none; }
19.link-block > ul > li {
20  font-size: 0.8em;
21  background-color: #eee;
22  border: 1px solid #ccc;
23  padding: 0.3em;
24  display: inline-block;
25}
26</style>
27<span></span><div class="link-block">
28
29**Links**
30
31* [Latest Release](https://crates.io/crates/boolinator/)
32* [Latest Docs](https://danielkeep.github.io/rust-boolinator/doc/boolinator/index.html)
33* [Repository](https://github.com/DanielKeep/rust-boolinator)
34
35<span></span></div>
36
37## Compatibility
38
39`boolinator` is tested against Rust 1.0+.  *Exhaustively* so.
40
41*/
42// Can't have undocumented APIs!  Nosiree!
43#![deny(missing_docs)]
44
45/**
46This trait defines a number of combinator-style methods for use with `bool` values.
47
48In general, `true`/`false` map to `Some(_)`/`None` and `Ok(_)`/`Err(_)` respectively.
49*/
50pub trait Boolinator: Sized {
51    /**
52    If this value is `true`, returns `Some(())`; `None` otherwise.
53    */
54    fn as_option(self) -> Option<()>;
55
56    /**
57    If this value is `true`, returns `Some(some)`; `None` otherwise.
58    */
59    fn as_some<T>(self, some: T) -> Option<T>;
60
61    /**
62    If this value is `true`, returns `Some(some())`; `None` otherwise. 
63    */
64    fn as_some_from<T, F>(self, some: F) -> Option<T>
65    where F: FnOnce() -> T;
66
67    /**
68    If this value is `true`, returns `opt`; `None` otherwise. 
69    */
70    fn and_option<T>(self, opt: Option<T>) -> Option<T>;
71
72    /**
73    If this value is `true`, returns `opt()`; `None` otherwise. 
74    */
75    fn and_option_from<T, F>(self, opt: F) -> Option<T>
76    where F: FnOnce() -> Option<T>;
77
78    /**
79    If this value is `true`, returns `Ok(ok)`; `Err(err)` otherwise. 
80    */
81    fn as_result<T, E>(self, ok: T, err: E) -> Result<T, E>;
82
83    /**
84    If this value is `true`, returns `Ok(ok())`; `Err(err())` otherwise. 
85    */
86    fn as_result_from<T, E, F, G>(self, ok: F, err: G) -> Result<T, E>
87    where F: FnOnce() -> T, G: FnOnce() -> E;
88
89    /**
90    If this value is `true`, returns `Ok(())`; `Err(err)` otherwise.
91    */
92    fn ok_or<E>(self, err: E) -> Result<(), E>;
93
94    /**
95    If this value is `true`, returns `Ok(())`; `Err(err())` otherwise.
96    */
97    fn ok_or_else<E, G>(self, err: G) -> Result<(), E>
98    where G: FnOnce() -> E;
99
100    /**
101    If this value is `true`, panics with `msg`; does nothing otherwise.
102    */
103    fn expect(self, msg: &str);
104}
105
106impl Boolinator for bool {
107    #[inline]
108    fn as_option(self) -> Option<()> {
109        if self { Some(()) } else { None }
110    }
111
112    #[inline]
113    fn as_some<T>(self, some: T) -> Option<T> {
114        if self { Some(some) } else { None }
115    }
116
117    #[inline]
118    fn as_some_from<T, F>(self, some: F) -> Option<T>
119    where F: FnOnce() -> T {
120        if self { Some(some()) } else { None }
121    }
122
123    #[inline]
124    fn and_option<T>(self, opt: Option<T>) -> Option<T> {
125        if self { opt } else { None }
126    }
127
128    #[inline]
129    fn and_option_from<T, F>(self, opt: F) -> Option<T>
130    where F: FnOnce() -> Option<T> {
131        if self { opt() } else { None }
132    }
133
134    #[inline]
135    fn as_result<T, E>(self, ok: T, err: E) -> Result<T, E> {
136        if self { Ok(ok) } else { Err(err) }
137    }
138
139    #[inline]
140    fn as_result_from<T, E, F, G>(self, ok: F, err: G) -> Result<T, E>
141    where F: FnOnce() -> T, G: FnOnce() -> E {
142        if self { Ok(ok()) } else { Err(err()) }
143    }
144
145    #[inline]
146    fn ok_or<E>(self, err: E) -> Result<(), E> {
147        if self { Ok(()) } else { Err(err) }
148    }
149
150    #[inline]
151    fn ok_or_else<E, G>(self, err: G) -> Result<(), E>
152    where G: FnOnce() -> E {
153        if self { Ok(()) } else { Err(err()) }
154    }
155    
156    #[inline]
157    fn expect(self, msg: &str) {
158        if self { () } else { panic!("{}", msg) }
159    }
160}
161
162/*
163Serious code must have serious tests, and Boolinator is serious business!
164*/
165#[cfg(test)]
166mod tests {
167    use super::Boolinator; // as opposed to the original NES version.
168
169    #[test]
170    fn test_as_option() {
171        // Very test.
172        assert_eq!(true.as_option(), Some(()));
173        assert_eq!(false.as_option(), None);
174    }
175
176    #[test]
177    fn test_as_some() {
178        // Much serious.
179        let love = true;
180        let everybody = love.as_some("body").expect("needs");
181        assert_eq!(everybody, "body");
182
183        assert_eq!((!love).as_some("money can buy"), None);
184    }
185
186    #[test]
187    fn test_as_some_from() {
188        // Wow.
189        let mothers = vec![true, false, false, true, false, true];
190        assert!(mothers.into_iter()
191            .map(|e| e.as_some_from(|| Some("em")))
192            .filter(Option::is_some)
193            .count() > 0);
194    }
195
196    #[test]
197    fn test_and_option() {
198        // Such original.
199        assert_eq!(true.and_option(Some("fries with that")), Some("fries with that"));
200        assert_eq!(false.and_option(Some("fries with that")), None);
201        assert_eq!(true.and_option(None), None::<()>);
202        assert_eq!(false.and_option(None), None::<()>);
203    }
204
205    #[test]
206    fn test_and_option_from() {
207        // Such original.
208        assert_eq!(true.and_option_from(|| Some("chips too, guv'")), Some("chips too, guv'"));
209        assert_eq!(false.and_option_from(|| Some("chips too, guv'")), None);
210        assert_eq!(true.and_option_from(|| None), None::<()>);
211        assert_eq!(false.and_option_from(|| None), None::<()>);
212    }
213
214    #[test]
215    fn test_as_result() {
216        // Very result.
217        assert_eq!(true.as_result("now; ", ", what?"),   Ok("now; "));
218        assert_eq!(false.as_result("now; ", ", what?"),  Err(", what?"));
219    }
220
221    #[test]
222    fn test_as_result_from() {
223        // Code good.
224        assert_eq!(true.as_result_from(|| "four space indent", || "anything else"), Ok("four space indent"));
225        assert_eq!(false.as_result_from(|| "four space indent", || "anything else"), Err("anything else"));
226    }
227
228    #[test]
229    fn test_ok_or() {
230        // Ok.
231        let mut annie = true;
232        assert_eq!(annie.ok_or("hit back"), Ok(()));
233        annie = false;
234        assert_eq!(annie.ok_or("hit back"), Err("hit back"));
235    }
236
237    #[test]
238    fn test_ok_or_else() {
239        // Ok.
240        let mut annie = true;
241        assert_eq!(annie.ok_or_else(|| "hit back"), Ok(()));
242        annie = false;
243        assert_eq!(annie.ok_or_else(|| "hit back"), Err("hit back"));
244    }
245
246    const DREAMS: &'static str = "love and financial security";
247
248    #[test]
249    fn test_expect() {
250        // Movies lie.
251        true.expect(DREAMS);
252    }
253
254    #[test]
255    #[should_panic]
256    fn test_expect_reality() {
257        // Send hugs.
258        false.expect(DREAMS);
259    }
260}