to_true/lib.rs
1#![no_std]
2#![doc = include_str!("../README.md")]
3
4#[doc = include_str!("../README.md")]
5pub trait ToTrue: Sized {
6 /// Run `f` when `*self == false`, then assign `*self` to `true`
7 fn to_true<F, R>(&mut self, f: F) -> Option<R>
8 where F: FnOnce() -> R;
9
10 /// Run `f` when `*self == true`, then assign `*self` to `false`
11 fn to_false<F, R>(&mut self, f: F) -> Option<R>
12 where F: FnOnce() -> R;
13}
14impl ToTrue for bool {
15 fn to_true<F, R>(&mut self, f: F) -> Option<R>
16 where F: FnOnce() -> R,
17 {
18 if *self {
19 None
20 } else {
21 *self = true;
22 Some(f())
23 }
24 }
25
26 fn to_false<F, R>(&mut self, f: F) -> Option<R>
27 where F: FnOnce() -> R,
28 {
29 if *self {
30 *self = false;
31 Some(f())
32 } else {
33 None
34 }
35 }
36}
37
38/// ```
39/// # use to_true::InTrue;
40/// let mut state = false;
41/// let mut n = 0;
42///
43/// assert_eq!(state.in_true(|| n += 1), None);
44/// assert_eq!((n, state), (0, true));
45///
46/// assert_eq!(state.in_true(|| n += 1), Some(()));
47/// assert_eq!((n, state), (1, true));
48///
49/// assert_eq!(state.in_false(|| n += 1), None);
50/// assert_eq!((n, state), (1, false));
51///
52/// assert_eq!(state.in_false(|| n += 1), Some(()));
53/// assert_eq!((n, state), (2, false));
54/// ```
55pub trait InTrue: Sized {
56 /// Run `f` when `*self == true`, then assign `*self` to `true`
57 fn in_true<F, R>(&mut self, f: F) -> Option<R>
58 where F: FnOnce() -> R;
59
60 /// Run `f` when `*self == false`, then assign `*self` to `false`
61 fn in_false<F, R>(&mut self, f: F) -> Option<R>
62 where F: FnOnce() -> R;
63}
64impl InTrue for bool {
65 fn in_true<F, R>(&mut self, f: F) -> Option<R>
66 where F: FnOnce() -> R,
67 {
68 let old = *self;
69 *self = true;
70 old.then(f)
71 }
72
73 fn in_false<F, R>(&mut self, f: F) -> Option<R>
74 where F: FnOnce() -> R,
75 {
76 let old = *self;
77 *self = false;
78 (!old).then(f)
79 }
80}
81
82/// A closure that does not run on the first call
83///
84/// # Examples
85///
86/// ```
87/// let mut n = 0;
88/// let mut f = to_true::skip(|| {n += 1; n});
89///
90/// assert_eq!(f(), None);
91/// assert_eq!(f(), Some(1));
92/// assert_eq!(f(), Some(2));
93/// ```
94pub fn skip<R>(mut f: impl FnMut() -> R) -> impl FnMut() -> Option<R> {
95 let mut state = false;
96 move || {
97 state.in_true(&mut f)
98 }
99}
100
101/// A closure that is runs only once
102///
103/// # Examples
104///
105/// ```
106/// let mut n = 0;
107/// let mut f = to_true::once(|| {n += 1; n});
108///
109/// assert_eq!(f(), Some(1));
110/// assert_eq!(f(), None);
111/// assert_eq!(f(), None);
112/// # drop(f);
113/// assert_eq!(n, 1);
114/// ```
115pub fn once<R>(f: impl FnOnce() -> R) -> impl FnMut() -> Option<R> {
116 let mut f = Some(f);
117 move || {
118 f.take().map(|f| f())
119 }
120}