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