| Daniel Cheng | cd23b8b | 2022-09-16 17:16:24 | [diff] [blame] | 1 | // Copyright 2012 The Chromium Authors |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | // This defines helpful methods for dealing with Callbacks. Because Callbacks |
| 6 | // are implemented using templates, with a class per callback signature, adding |
| 7 | // methods to Callback<> itself is unattractive (lots of extra code gets |
| 8 | // generated). Instead, consider adding methods here. |
| 9 | |
| 10 | #ifndef BASE_FUNCTIONAL_CALLBACK_HELPERS_H_ |
| 11 | #define BASE_FUNCTIONAL_CALLBACK_HELPERS_H_ |
| 12 | |
| Kevin Lin | 1e19bc3 | 2023-03-30 16:36:24 | [diff] [blame] | 13 | #include <atomic> |
| Daniel Cheng | cd23b8b | 2022-09-16 17:16:24 | [diff] [blame] | 14 | #include <memory> |
| 15 | #include <ostream> |
| 16 | #include <type_traits> |
| 17 | #include <utility> |
| 18 | |
| Daniel Cheng | cd23b8b | 2022-09-16 17:16:24 | [diff] [blame] | 19 | #include "base/base_export.h" |
| 20 | #include "base/check.h" |
| 21 | #include "base/functional/bind.h" |
| 22 | #include "base/functional/callback.h" |
| Paul Semel | 4c1e3e8 | 2022-10-24 09:20:54 | [diff] [blame] | 23 | #include "base/functional/callback_tags.h" |
| Daniel Cheng | cd23b8b | 2022-09-16 17:16:24 | [diff] [blame] | 24 | |
| 25 | namespace base { |
| 26 | |
| 27 | namespace internal { |
| 28 | |
| Daniel Cheng | cd23b8b | 2022-09-16 17:16:24 | [diff] [blame] | 29 | template <typename... Args> |
| 30 | class OnceCallbackHolder final { |
| 31 | public: |
| 32 | OnceCallbackHolder(OnceCallback<void(Args...)> callback, |
| 33 | bool ignore_extra_runs) |
| 34 | : callback_(std::move(callback)), ignore_extra_runs_(ignore_extra_runs) { |
| 35 | DCHECK(callback_); |
| 36 | } |
| 37 | OnceCallbackHolder(const OnceCallbackHolder&) = delete; |
| 38 | OnceCallbackHolder& operator=(const OnceCallbackHolder&) = delete; |
| 39 | |
| 40 | void Run(Args... args) { |
| Venkatesh Srinivas | 99db1f9 | 2023-03-19 06:33:07 | [diff] [blame] | 41 | if (has_run_.exchange(true, std::memory_order_relaxed)) { |
| Daniel Cheng | cd23b8b | 2022-09-16 17:16:24 | [diff] [blame] | 42 | CHECK(ignore_extra_runs_) << "Both OnceCallbacks returned by " |
| 43 | "base::SplitOnceCallback() were run. " |
| 44 | "At most one of the pair should be run."; |
| 45 | return; |
| 46 | } |
| 47 | DCHECK(callback_); |
| 48 | std::move(callback_).Run(std::forward<Args>(args)...); |
| 49 | } |
| 50 | |
| 51 | private: |
| Kevin Lin | 1e19bc3 | 2023-03-30 16:36:24 | [diff] [blame] | 52 | std::atomic<bool> has_run_{false}; |
| Daniel Cheng | cd23b8b | 2022-09-16 17:16:24 | [diff] [blame] | 53 | base::OnceCallback<void(Args...)> callback_; |
| 54 | const bool ignore_extra_runs_; |
| 55 | }; |
| 56 | |
| Paul Semel | 1aba415 | 2023-09-28 16:46:13 | [diff] [blame] | 57 | template <typename... Args> |
| 58 | void ForwardRepeatingCallbacksImpl( |
| 59 | std::vector<RepeatingCallback<void(Args...)>> cbs, |
| 60 | Args... args) { |
| 61 | for (auto& cb : cbs) { |
| 62 | if (cb) { |
| 63 | cb.Run(std::forward<Args>(args)...); |
| 64 | } |
| 65 | } |
| 66 | } |
| 67 | |
| Daniel Cheng | cd23b8b | 2022-09-16 17:16:24 | [diff] [blame] | 68 | } // namespace internal |
| 69 | |
| Paul Semel | 1aba415 | 2023-09-28 16:46:13 | [diff] [blame] | 70 | // Wraps the given RepeatingCallbacks and return one RepeatingCallbacks with an |
| 71 | // identical signature. On invocation of this callback, all the given |
| 72 | // RepeatingCallbacks will be called with the same arguments. Unbound arguments |
| 73 | // must be copyable. |
| 74 | template <typename... Args> |
| 75 | RepeatingCallback<void(Args...)> ForwardRepeatingCallbacks( |
| 76 | std::initializer_list<RepeatingCallback<void(Args...)>>&& cbs) { |
| 77 | std::vector<RepeatingCallback<void(Args...)>> v( |
| 78 | std::forward<std::initializer_list<RepeatingCallback<void(Args...)>>>( |
| 79 | cbs)); |
| 80 | return BindRepeating(&internal::ForwardRepeatingCallbacksImpl<Args...>, |
| 81 | std::move(v)); |
| 82 | } |
| 83 | |
| Daniel Cheng | cd23b8b | 2022-09-16 17:16:24 | [diff] [blame] | 84 | // Wraps the given OnceCallback and returns two OnceCallbacks with an identical |
| 85 | // signature. On first invokation of either returned callbacks, the original |
| 86 | // callback is invoked. Invoking the remaining callback results in a crash. |
| 87 | template <typename... Args> |
| 88 | std::pair<OnceCallback<void(Args...)>, OnceCallback<void(Args...)>> |
| 89 | SplitOnceCallback(OnceCallback<void(Args...)> callback) { |
| 90 | if (!callback) { |
| 91 | // Empty input begets two empty outputs. |
| 92 | return std::make_pair(OnceCallback<void(Args...)>(), |
| 93 | OnceCallback<void(Args...)>()); |
| 94 | } |
| 95 | using Helper = internal::OnceCallbackHolder<Args...>; |
| 96 | auto wrapped_once = base::BindRepeating( |
| 97 | &Helper::Run, std::make_unique<Helper>(std::move(callback), |
| 98 | /*ignore_extra_runs=*/false)); |
| 99 | return std::make_pair(wrapped_once, wrapped_once); |
| 100 | } |
| 101 | |
| Evan Stade | 5df7469 | 2023-10-02 23:15:57 | [diff] [blame] | 102 | // Adapts `callback` for use in a context which is expecting a callback with |
| 103 | // additional parameters. Returns a null callback if `callback` is null. |
| 104 | // |
| 105 | // Usage: |
| Keren Zhu | 9cd105c8 | 2024-08-03 00:00:12 | [diff] [blame] | 106 | // bool LogError(char* error_message) { |
| Evan Stade | 5df7469 | 2023-10-02 23:15:57 | [diff] [blame] | 107 | // if (error_message) { |
| 108 | // cout << "Log: " << error_message << endl; |
| Keren Zhu | 9cd105c8 | 2024-08-03 00:00:12 | [diff] [blame] | 109 | // return false; |
| Evan Stade | 5df7469 | 2023-10-02 23:15:57 | [diff] [blame] | 110 | // } |
| Keren Zhu | 9cd105c8 | 2024-08-03 00:00:12 | [diff] [blame] | 111 | // return true; |
| Evan Stade | 5df7469 | 2023-10-02 23:15:57 | [diff] [blame] | 112 | // } |
| Keren Zhu | 9cd105c8 | 2024-08-03 00:00:12 | [diff] [blame] | 113 | // base::RepeatingCallback<bool(int, char*)> cb = |
| Evan Stade | 5df7469 | 2023-10-02 23:15:57 | [diff] [blame] | 114 | // base::IgnoreArgs<int>(base::BindRepeating(&LogError)); |
| Keren Zhu | 9cd105c8 | 2024-08-03 00:00:12 | [diff] [blame] | 115 | // CHECK_EQ(true, cb.Run(42, nullptr)); |
| Evan Stade | 5df7469 | 2023-10-02 23:15:57 | [diff] [blame] | 116 | // |
| 117 | // Note in the example above that the type(s) passed to `IgnoreArgs` |
| 118 | // represent the additional prepended parameters (those which will be |
| 119 | // "ignored"). |
| Keren Zhu | 9cd105c8 | 2024-08-03 00:00:12 | [diff] [blame] | 120 | template <typename... Preargs, typename... Args, typename R> |
| 121 | RepeatingCallback<R(Preargs..., Args...)> IgnoreArgs( |
| 122 | RepeatingCallback<R(Args...)> callback) { |
| L. David Baron | ca7056e | 2024-01-11 21:59:43 | [diff] [blame] | 123 | return callback ? ::base::BindRepeating( |
| Keren Zhu | 9cd105c8 | 2024-08-03 00:00:12 | [diff] [blame] | 124 | [](RepeatingCallback<R(Args...)> callback, Preargs..., |
| 125 | Args... args) { |
| 126 | return std::move(callback).Run( |
| 127 | std::forward<Args>(args)...); |
| Evan Stade | 5df7469 | 2023-10-02 23:15:57 | [diff] [blame] | 128 | }, |
| 129 | std::move(callback)) |
| Keren Zhu | 9cd105c8 | 2024-08-03 00:00:12 | [diff] [blame] | 130 | : RepeatingCallback<R(Preargs..., Args...)>(); |
| Nicolas Dossou-Gbete | 51290c2f | 2022-10-19 12:50:34 | [diff] [blame] | 131 | } |
| 132 | |
| Evan Stade | 5df7469 | 2023-10-02 23:15:57 | [diff] [blame] | 133 | // As above, but for OnceCallback. |
| Keren Zhu | 9cd105c8 | 2024-08-03 00:00:12 | [diff] [blame] | 134 | template <typename... Preargs, typename... Args, typename R> |
| 135 | OnceCallback<R(Preargs..., Args...)> IgnoreArgs( |
| 136 | OnceCallback<R(Args...)> callback) { |
| L. David Baron | ca7056e | 2024-01-11 21:59:43 | [diff] [blame] | 137 | return callback ? ::base::BindOnce( |
| Keren Zhu | 9cd105c8 | 2024-08-03 00:00:12 | [diff] [blame] | 138 | [](OnceCallback<R(Args...)> callback, Preargs..., |
| Evan Stade | 5df7469 | 2023-10-02 23:15:57 | [diff] [blame] | 139 | Args... args) { |
| Keren Zhu | 9cd105c8 | 2024-08-03 00:00:12 | [diff] [blame] | 140 | return std::move(callback).Run( |
| 141 | std::forward<Args>(args)...); |
| Evan Stade | 5df7469 | 2023-10-02 23:15:57 | [diff] [blame] | 142 | }, |
| 143 | std::move(callback)) |
| Keren Zhu | 9cd105c8 | 2024-08-03 00:00:12 | [diff] [blame] | 144 | : OnceCallback<R(Preargs..., Args...)>(); |
| Nicolas Dossou-Gbete | 51290c2f | 2022-10-19 12:50:34 | [diff] [blame] | 145 | } |
| 146 | |
| Daniel Cheng | cd23b8b | 2022-09-16 17:16:24 | [diff] [blame] | 147 | // ScopedClosureRunner is akin to std::unique_ptr<> for Closures. It ensures |
| 148 | // that the Closure is executed no matter how the current scope exits. |
| 149 | // If you are looking for "ScopedCallback", "CallbackRunner", or |
| 150 | // "CallbackScoper" this is the class you want. |
| 151 | class BASE_EXPORT ScopedClosureRunner { |
| 152 | public: |
| 153 | ScopedClosureRunner(); |
| Ian Vollick | cf2a386 | 2024-07-11 21:00:37 | [diff] [blame] | 154 | [[nodiscard]] explicit ScopedClosureRunner(OnceClosure closure); |
| Daniel Cheng | cd23b8b | 2022-09-16 17:16:24 | [diff] [blame] | 155 | ScopedClosureRunner(ScopedClosureRunner&& other); |
| 156 | // Runs the current closure if it's set, then replaces it with the closure |
| 157 | // from |other|. This is akin to how unique_ptr frees the contained pointer in |
| 158 | // its move assignment operator. If you need to explicitly avoid running any |
| 159 | // current closure, use ReplaceClosure(). |
| 160 | ScopedClosureRunner& operator=(ScopedClosureRunner&& other); |
| 161 | ~ScopedClosureRunner(); |
| 162 | |
| 163 | explicit operator bool() const { return !!closure_; } |
| 164 | |
| 165 | // Calls the current closure and resets it, so it wont be called again. |
| 166 | void RunAndReset(); |
| 167 | |
| 168 | // Replaces closure with the new one releasing the old one without calling it. |
| 169 | void ReplaceClosure(OnceClosure closure); |
| 170 | |
| 171 | // Releases the Closure without calling. |
| 172 | [[nodiscard]] OnceClosure Release(); |
| 173 | |
| 174 | private: |
| 175 | OnceClosure closure_; |
| 176 | }; |
| 177 | |
| 178 | // Returns a placeholder type that will implicitly convert into a null callback, |
| Arthur Sonzogni | e5fff99c | 2024-02-21 15:58:24 | [diff] [blame] | 179 | // similar to how std::nullopt / std::nullptr work in conjunction with |
| 180 | // std::optional and various smart pointer types. |
| Daniel Cheng | cd23b8b | 2022-09-16 17:16:24 | [diff] [blame] | 181 | constexpr auto NullCallback() { |
| 182 | return internal::NullCallbackTag(); |
| 183 | } |
| 184 | |
| 185 | // Returns a placeholder type that will implicitly convert into a callback that |
| Arthur Sonzogni | e5fff99c | 2024-02-21 15:58:24 | [diff] [blame] | 186 | // does nothing, similar to how std::nullopt / std::nullptr work in conjunction |
| 187 | // with std::optional and various smart pointer types. |
| Daniel Cheng | cd23b8b | 2022-09-16 17:16:24 | [diff] [blame] | 188 | constexpr auto DoNothing() { |
| 189 | return internal::DoNothingCallbackTag(); |
| 190 | } |
| 191 | |
| 192 | // Similar to the above, but with a type hint. Useful for disambiguating |
| 193 | // among multiple function overloads that take callbacks with different |
| 194 | // signatures: |
| 195 | // |
| 196 | // void F(base::OnceCallback<void()> callback); // 1 |
| 197 | // void F(base::OnceCallback<void(int)> callback); // 2 |
| 198 | // |
| 199 | // F(base::NullCallbackAs<void()>()); // calls 1 |
| 200 | // F(base::DoNothingAs<void(int)>()); // calls 2 |
| 201 | template <typename Signature> |
| 202 | constexpr auto NullCallbackAs() { |
| 203 | return internal::NullCallbackTag::WithSignature<Signature>(); |
| 204 | } |
| 205 | |
| 206 | template <typename Signature> |
| 207 | constexpr auto DoNothingAs() { |
| 208 | return internal::DoNothingCallbackTag::WithSignature<Signature>(); |
| 209 | } |
| 210 | |
| Paul Semel | 4c1e3e8 | 2022-10-24 09:20:54 | [diff] [blame] | 211 | // Similar to DoNothing above, but with bound arguments. This helper is useful |
| 212 | // for keeping objects alive until the callback runs. |
| 213 | // Example: |
| 214 | // |
| 215 | // void F(base::OnceCallback<void(int)> result_callback); |
| 216 | // |
| 217 | // std::unique_ptr<MyClass> ptr; |
| 218 | // F(base::DoNothingWithBoundArgs(std::move(ptr))); |
| 219 | template <typename... Args> |
| 220 | constexpr auto DoNothingWithBoundArgs(Args&&... args) { |
| 221 | return internal::DoNothingCallbackTag::WithBoundArguments( |
| 222 | std::forward<Args>(args)...); |
| 223 | } |
| 224 | |
| Sylvain Defresne | b5363df | 2023-10-30 19:44:29 | [diff] [blame] | 225 | // Creates a callback that returns `value` when invoked. This helper is useful |
| 226 | // for implementing factories that return a constant value. |
| 227 | // Example: |
| 228 | // |
| 229 | // void F(base::OnceCallback<Widget()> factory); |
| 230 | // |
| 231 | // Widget widget = ...; |
| 232 | // F(base::ReturnValueOnce(std::move(widget))); |
| 233 | template <typename T> |
| 234 | constexpr OnceCallback<T(void)> ReturnValueOnce(T value) { |
| 235 | static_assert(!std::is_reference_v<T>); |
| 236 | return base::BindOnce([](T value) { return value; }, std::move(value)); |
| 237 | } |
| 238 | |
| Daniel Cheng | cd23b8b | 2022-09-16 17:16:24 | [diff] [blame] | 239 | // Useful for creating a Closure that will delete a pointer when invoked. Only |
| 240 | // use this when necessary. In most cases MessageLoop::DeleteSoon() is a better |
| 241 | // fit. |
| 242 | template <typename T> |
| 243 | void DeletePointer(T* obj) { |
| 244 | delete obj; |
| 245 | } |
| 246 | |
| Sylvain Defresne | 953d539 | 2023-07-20 11:01:37 | [diff] [blame] | 247 | #if __OBJC__ |
| 248 | |
| 249 | // Creates an Objective-C block with the same signature as the corresponding |
| 250 | // callback. Can be used to implement a callback based API internally based |
| 251 | // on a block based Objective-C API. |
| 252 | // |
| 253 | // Overloaded to work with both repeating and one shot callbacks. Calling the |
| 254 | // block wrapping a base::OnceCallback<...> multiple times will crash (there |
| 255 | // is no way to mark the block as callable only once). Only use that when you |
| 256 | // know that Objective-C API will only invoke the block once. |
| 257 | template <typename R, typename... Args> |
| 258 | auto CallbackToBlock(base::OnceCallback<R(Args...)> callback) { |
| 259 | __block base::OnceCallback<R(Args...)> block_callback = std::move(callback); |
| 260 | return ^(Args... args) { |
| 261 | return std::move(block_callback).Run(std::forward<Args>(args)...); |
| 262 | }; |
| 263 | } |
| 264 | |
| 265 | template <typename R, typename... Args> |
| 266 | auto CallbackToBlock(base::RepeatingCallback<R(Args...)> callback) { |
| 267 | return ^(Args... args) { |
| 268 | return callback.Run(std::forward<Args>(args)...); |
| 269 | }; |
| 270 | } |
| 271 | |
| 272 | #endif // __OBJC__ |
| 273 | |
| Daniel Cheng | cd23b8b | 2022-09-16 17:16:24 | [diff] [blame] | 274 | } // namespace base |
| 275 | |
| 276 | #endif // BASE_FUNCTIONAL_CALLBACK_HELPERS_H_ |