1 /*
2 
3 // TODO: replace the 3 macros with 3 functions once they work correctly with
4 // reference arguments.
5 // (The returned closure must implement the for<'a> Fn(T, U<'a>)...
6 
7 
8 // TODO: replace the 3 macros/functions with a generic function when it can
9 // accept any number of arguments.
10 
11 /// Wraps a `FnMut` into a `Fn`
12 ///
13 /// This can be used to use a `FnMut` when a callack expects a `Fn`.
14 ///
15 /// # Note
16 ///
17 /// If the resulting `Fn` is called recursively, subsequent calls will be
18 /// no-ops.
19 pub fn immutify<F: FnMut(&mut Cursive)>(
20     f: F,
21 ) -> impl for<'s> Fn(&'s mut Cursive) {
22     let callback = RefCell::new(f);
23     move |s| {
24         // Here's the weird trick: if we're already borrowed,
25         // just ignored the callback.
26         if let Ok(mut f) = callback.try_borrow_mut() {
27             // Beeeaaah that's ugly.
28             // Why do we need to manually dereference here?
29             (&mut *f)(s);
30         }
31     }
32 }
33 
34 */
35 
36 /// Macro to wrap a `FnMut` with 1 argument into a `Fn`.
37 ///
38 /// This can wrap any `FnMut` with a single arguments (for example `&mut Cursive`).
39 ///
40 /// See [`immut2!`] and [`immut3!`] to support a different number of arguments.
41 ///
42 /// # Note
43 ///
44 /// If this function tries to call itself recursively (for example by
45 /// triggering an event in `Cursive`), the second call will be a no-op.
46 /// Enabling recursive calls would break the `FnMut` contract.
47 ///
48 /// In addition, due to weird interaction between Higher-rank trait bounds and
49 /// closures, you should use the result from the macro directly, and not
50 /// assign it to a variable.
51 ///
52 /// # Examples
53 ///
54 /// ```rust
55 /// # use cursive_core::{Cursive, immut1};
56 /// # fn main() {
57 /// # let mut siv = Cursive::new();
58 /// let mut i = 0;
59 /// // `Cursive::add_global_callback` takes a `Fn(&mut Cursive)`
60 /// siv.add_global_callback(
61 ///     'q',
62 ///     immut1!(move |s: &mut Cursive| {
63 ///         // But here we mutate the environment! Crazy!
64 ///         i += 1;
65 ///         if i == 5 {
66 ///             s.quit();
67 ///         }
68 ///     }),
69 /// );
70 /// # }
71 /// ```
72 #[macro_export]
73 macro_rules! immut1 {
74     ($f:expr ; else $else:expr) => {{
75         let callback = ::std::cell::RefCell::new($f);
76         move |s| {
77             if let ::std::result::Result::Ok(mut f) = callback.try_borrow_mut()
78             {
79                 (&mut *f)(s)
80             } else {
81                 $else
82             }
83         }
84     }};
85     ($f:expr) => {{
86         let callback = ::std::cell::RefCell::new($f);
87         move |s| {
88             if let ::std::result::Result::Ok(mut f) = callback.try_borrow_mut()
89             {
90                 (&mut *f)(s);
91             }
92         }
93     }};
94 }
95 
96 /// Macro to wrap a `FnOnce` with 1 argument into a `FnMut`.
97 ///
98 /// This can wrap any `FnOnce` with a single argument (for example `&mut Cursive`).
99 ///
100 /// # Note
101 ///
102 /// If the resulting function is called multiple times, only the first call will trigger the
103 /// wrapped `FnOnce`. All subsequent calls will be no-ops.
104 ///
105 /// In addition, due to weird interaction between Higher-rank trait bounds and
106 /// closures, you should use the result from the macro directly, and not
107 /// assign it to a variable.
108 #[macro_export]
109 macro_rules! once1 {
110     ($f:expr) => {{
111         let mut callback = ::std::option::Option::Some($f);
112         move |s| {
113             if let ::std::option::Option::Some(f) = callback.take() {
114                 f(s);
115             }
116         }
117     }};
118 }
119 
120 /// Macro to wrap a `FnMut` with 2 arguments into a `Fn`.
121 ///
122 /// This can wrap any `FnMut` with two arguments.
123 ///
124 /// See [`immut1!`] and [`immut3!`] to support a different number of arguments.
125 ///
126 /// # Note
127 ///
128 /// If this function tries to call itself recursively (for example by
129 /// triggering an event in `Cursive`), the second call will be a no-op.
130 /// Enabling recursive calls would break the `FnMut` contract.
131 ///
132 /// In addition, due to weird interaction between Higher-rank trait bounds and
133 /// closures, you should use the result from the macro directly, and not
134 /// assign it to a variable.
135 #[macro_export]
136 macro_rules! immut2 {
137     ($f:expr ; else $else:expr) => {{
138         let callback = ::std::cell::RefCell::new($f);
139         move |s, t| {
140             if let ::std::result::Result::Ok(mut f) = callback.try_borrow_mut()
141             {
142                 (&mut *f)(s, t)
143             } else {
144                 $else
145             }
146         }
147     }};
148     ($f:expr) => {{
149         let callback = ::std::cell::RefCell::new($f);
150         move |s, t| {
151             if let Ok(mut f) = callback.try_borrow_mut() {
152                 (&mut *f)(s, t);
153             }
154         }
155     }};
156 }
157 
158 /// Macro to wrap a `FnMut` with 3 arguments into a `Fn`.
159 ///
160 /// This can wrap any `FnMut` with three arguments.
161 ///
162 /// See [`immut1!`] and [`immut2!`] to support a different number of arguments.
163 ///
164 /// # Note
165 ///
166 /// If this function tries to call itself recursively (for example by
167 /// triggering an event in `Cursive`), the second call will be a no-op.
168 /// Enabling recursive calls would break the `FnMut` contract.
169 ///
170 /// In addition, due to weird interaction between Higher-rank trait bounds and
171 /// closures, you should use the result from the macro directly, and not
172 /// assign it to a variable.
173 #[macro_export]
174 macro_rules! immut3 {
175     ($f:expr ; else $else:expr) => {{
176         let callback = ::std::cell::RefCell::new($f);
177         move |s, t, t| {
178             if let ::std::result::Result::Ok(mut f) = callback.try_borrow_mut()
179             {
180                 (&mut *f)(s, t, u)
181             } else {
182                 $else
183             }
184         }
185     }};
186     ($f:expr) => {{
187         let callback = ::std::cell::RefCell::new($f);
188         move |s, t, u| {
189             if let Ok(mut f) = callback.try_borrow_mut() {
190                 (&mut *f)(s, t, u);
191             }
192         }
193     }};
194 }
195