// Copyright 2012 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // This defines helpful methods for dealing with Callbacks. Because Callbacks // are implemented using templates, with a class per callback signature, adding // methods to Callback<> itself is unattractive (lots of extra code gets // generated). Instead, consider adding methods here. #ifndef BASE_FUNCTIONAL_CALLBACK_HELPERS_H_ #define BASE_FUNCTIONAL_CALLBACK_HELPERS_H_ #include #include #include #include #include #include "base/atomicops.h" #include "base/base_export.h" #include "base/check.h" #include "base/functional/bind.h" #include "base/functional/callback.h" #include "base/functional/callback_tags.h" namespace base { namespace internal { template struct IsBaseCallbackImpl : std::false_type {}; template struct IsBaseCallbackImpl> : std::true_type {}; template struct IsBaseCallbackImpl> : std::true_type {}; } // namespace internal // IsBaseCallback is satisfied if and only if T is an instantiation of // base::OnceCallback or base::RepeatingCallback. template concept IsBaseCallback = internal::IsBaseCallbackImpl>::value; namespace internal { template class OnceCallbackHolder final { public: OnceCallbackHolder(OnceCallback callback, bool ignore_extra_runs) : callback_(std::move(callback)), ignore_extra_runs_(ignore_extra_runs) { DCHECK(callback_); } OnceCallbackHolder(const OnceCallbackHolder&) = delete; OnceCallbackHolder& operator=(const OnceCallbackHolder&) = delete; void Run(Args... args) { if (has_run_.exchange(true, std::memory_order_relaxed)) { CHECK(ignore_extra_runs_) << "Both OnceCallbacks returned by " "base::SplitOnceCallback() were run. " "At most one of the pair should be run."; return; } DCHECK(callback_); std::move(callback_).Run(std::forward(args)...); } private: std::atomic has_run_{false}; base::OnceCallback callback_; const bool ignore_extra_runs_; }; template void ForwardRepeatingCallbacksImpl( std::vector> cbs, Args... args) { for (auto& cb : cbs) { if (cb) { cb.Run(std::forward(args)...); } } } } // namespace internal // Wraps the given RepeatingCallbacks and return one RepeatingCallbacks with an // identical signature. On invocation of this callback, all the given // RepeatingCallbacks will be called with the same arguments. Unbound arguments // must be copyable. template RepeatingCallback ForwardRepeatingCallbacks( std::initializer_list>&& cbs) { std::vector> v( std::forward>>( cbs)); return BindRepeating(&internal::ForwardRepeatingCallbacksImpl, std::move(v)); } // Wraps the given OnceCallback and returns two OnceCallbacks with an identical // signature. On first invokation of either returned callbacks, the original // callback is invoked. Invoking the remaining callback results in a crash. template std::pair, OnceCallback> SplitOnceCallback(OnceCallback callback) { if (!callback) { // Empty input begets two empty outputs. return std::make_pair(OnceCallback(), OnceCallback()); } using Helper = internal::OnceCallbackHolder; auto wrapped_once = base::BindRepeating( &Helper::Run, std::make_unique(std::move(callback), /*ignore_extra_runs=*/false)); return std::make_pair(wrapped_once, wrapped_once); } // Adapts `callback` for use in a context which is expecting a callback with // additional parameters. Returns a null callback if `callback` is null. // // Usage: // void LogError(char* error_message) { // if (error_message) { // cout << "Log: " << error_message << endl; // } // } // base::RepeatingCallback cb = // base::IgnoreArgs(base::BindRepeating(&LogError)); // cb.Run(42, nullptr); // // Note in the example above that the type(s) passed to `IgnoreArgs` // represent the additional prepended parameters (those which will be // "ignored"). template RepeatingCallback IgnoreArgs( RepeatingCallback callback) { return callback ? ::base::BindRepeating( [](RepeatingCallback callback, Preargs..., Args... args) { std::move(callback).Run(std::forward(args)...); }, std::move(callback)) : RepeatingCallback(); } // As above, but for OnceCallback. template OnceCallback IgnoreArgs( OnceCallback callback) { return callback ? ::base::BindOnce( [](OnceCallback callback, Preargs..., Args... args) { std::move(callback).Run(std::forward(args)...); }, std::move(callback)) : OnceCallback(); } // ScopedClosureRunner is akin to std::unique_ptr<> for Closures. It ensures // that the Closure is executed no matter how the current scope exits. // If you are looking for "ScopedCallback", "CallbackRunner", or // "CallbackScoper" this is the class you want. class BASE_EXPORT ScopedClosureRunner { public: ScopedClosureRunner(); explicit ScopedClosureRunner(OnceClosure closure); ScopedClosureRunner(ScopedClosureRunner&& other); // Runs the current closure if it's set, then replaces it with the closure // from |other|. This is akin to how unique_ptr frees the contained pointer in // its move assignment operator. If you need to explicitly avoid running any // current closure, use ReplaceClosure(). ScopedClosureRunner& operator=(ScopedClosureRunner&& other); ~ScopedClosureRunner(); explicit operator bool() const { return !!closure_; } // Calls the current closure and resets it, so it wont be called again. void RunAndReset(); // Replaces closure with the new one releasing the old one without calling it. void ReplaceClosure(OnceClosure closure); // Releases the Closure without calling. [[nodiscard]] OnceClosure Release(); private: OnceClosure closure_; }; // Returns a placeholder type that will implicitly convert into a null callback, // similar to how std::nullopt / std::nullptr work in conjunction with // std::optional and various smart pointer types. constexpr auto NullCallback() { return internal::NullCallbackTag(); } // Returns a placeholder type that will implicitly convert into a callback that // does nothing, similar to how std::nullopt / std::nullptr work in conjunction // with std::optional and various smart pointer types. constexpr auto DoNothing() { return internal::DoNothingCallbackTag(); } // Similar to the above, but with a type hint. Useful for disambiguating // among multiple function overloads that take callbacks with different // signatures: // // void F(base::OnceCallback callback); // 1 // void F(base::OnceCallback callback); // 2 // // F(base::NullCallbackAs()); // calls 1 // F(base::DoNothingAs()); // calls 2 template constexpr auto NullCallbackAs() { return internal::NullCallbackTag::WithSignature(); } template constexpr auto DoNothingAs() { return internal::DoNothingCallbackTag::WithSignature(); } // Similar to DoNothing above, but with bound arguments. This helper is useful // for keeping objects alive until the callback runs. // Example: // // void F(base::OnceCallback result_callback); // // std::unique_ptr ptr; // F(base::DoNothingWithBoundArgs(std::move(ptr))); template constexpr auto DoNothingWithBoundArgs(Args&&... args) { return internal::DoNothingCallbackTag::WithBoundArguments( std::forward(args)...); } // Creates a callback that returns `value` when invoked. This helper is useful // for implementing factories that return a constant value. // Example: // // void F(base::OnceCallback factory); // // Widget widget = ...; // F(base::ReturnValueOnce(std::move(widget))); template constexpr OnceCallback ReturnValueOnce(T value) { static_assert(!std::is_reference_v); return base::BindOnce([](T value) { return value; }, std::move(value)); } // Useful for creating a Closure that will delete a pointer when invoked. Only // use this when necessary. In most cases MessageLoop::DeleteSoon() is a better // fit. template void DeletePointer(T* obj) { delete obj; } #if __OBJC__ // Creates an Objective-C block with the same signature as the corresponding // callback. Can be used to implement a callback based API internally based // on a block based Objective-C API. // // Overloaded to work with both repeating and one shot callbacks. Calling the // block wrapping a base::OnceCallback<...> multiple times will crash (there // is no way to mark the block as callable only once). Only use that when you // know that Objective-C API will only invoke the block once. template auto CallbackToBlock(base::OnceCallback callback) { __block base::OnceCallback block_callback = std::move(callback); return ^(Args... args) { return std::move(block_callback).Run(std::forward(args)...); }; } template auto CallbackToBlock(base::RepeatingCallback callback) { return ^(Args... args) { return callback.Run(std::forward(args)...); }; } #endif // __OBJC__ } // namespace base #endif // BASE_FUNCTIONAL_CALLBACK_HELPERS_H_