and_then_some/
lib.rs

1//! Provides an extension trait for `bool` with methods that return `Option<T>`.
2
3#![no_std]
4#![forbid(unsafe_code)]
5#![warn(missing_docs)]
6
7/// Extends the primitive `bool` type with four methods to create a `Option`s.
8pub trait BoolExt {
9    /// `if self { value } else { None }`
10    fn and<T>(self, value: Option<T>) -> Option<T>;
11
12    /// `if self { Some(value) } else { None }`
13    fn and_some<T>(self, value: T) -> Option<T>;
14
15    /// `if self { f() } else { None }`
16    fn and_then<T>(self, f: impl FnOnce() -> Option<T>) -> Option<T>;
17
18    /// `if self { Some(f()) } else { None }`
19    fn and_then_some<T>(self, f: impl FnOnce() -> T) -> Option<T>;
20}
21
22impl BoolExt for bool {
23    fn and<T>(self, value: Option<T>) -> Option<T> {
24        if self { value } else { None }
25    }
26
27    fn and_some<T>(self, value: T) -> Option<T> {
28        if self { Some(value) } else { None }
29    }
30
31    fn and_then<T>(self, f: impl FnOnce() -> Option<T>) -> Option<T> {
32        if self { f() } else { None }
33    }
34
35    fn and_then_some<T>(self, f: impl FnOnce() -> T) -> Option<T> {
36        if self { Some(f()) } else { None }
37    }
38}
39
40#[cfg(test)]
41mod tests {
42    use super::BoolExt;
43
44    #[test]
45    fn and() {
46        assert_eq!(true.and(Some("hello")), Some("hello"));
47        assert_eq!(true.and(Option::<&str>::None), None);
48        assert_eq!(false.and(Some("world")), None);
49        assert_eq!(false.and(Option::<&str>::None), None);
50    }
51
52    #[test]
53    fn and_some() {
54        assert_eq!(true.and_some(()), Some(()));
55        assert_eq!(false.and_some(()), None);
56    }
57
58    #[test]
59    fn and_then() {
60        assert_eq!(true.and_then(|| Some(1 + 1)), Some(2));
61        assert_eq!(true.and_then(|| Option::<u32>::None), None);
62        assert_eq!(false.and_then(|| Some(1 + 1)), None);
63        assert_eq!(false.and_then(|| Option::<u32>::None), None);
64    }
65
66    #[test]
67    fn and_then_some() {
68        assert_eq!(true.and_then_some(|| true), Some(true));
69        assert_eq!(true.and_then_some(|| false), Some(false));
70        assert_eq!(false.and_then_some(|| true), None);
71        assert_eq!(false.and_then_some(|| false), None);
72    }
73
74    #[test]
75    fn side_effects() {
76        let mut ct = 0;
77
78        let _ = true.and_then(|| {
79            ct += 1;
80            Some(())
81        });
82        assert_eq!(ct, 1);
83
84        let _ = false.and_then(|| {
85            ct += 1;
86            Some(())
87        });
88        assert_eq!(ct, 1);
89
90        let _ = true.and_then_some(|| ct += 1);
91        assert_eq!(ct, 2);
92
93        let _ = false.and_then_some(|| ct += 1);
94        assert_eq!(ct, 2);
95    }
96}