xref: /aosp_15_r20/external/libchrome/mojo/public/cpp/bindings/callback_helpers.h (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_HELPERS_H_
6 #define MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_HELPERS_H_
7 
8 #include <memory>
9 #include <utility>
10 
11 #include "base/bind.h"
12 #include "base/callback.h"
13 #include "base/macros.h"
14 #include "base/memory/ptr_util.h"
15 
16 // This is a helper utility to wrap a base::OnceCallback such that if the
17 // callback is destructed before it has a chance to run (e.g. the callback is
18 // bound into a task and the task is dropped), it will be run the with
19 // default arguments passed into WrapCallbackWithDefaultInvokeIfNotRun.
20 // Alternatively, it will run the delete closure passed to
21 // WrapCallbackWithDropHandler.
22 //
23 // These helpers are intended for use on the client side of a mojo interface,
24 // where users want to know if their individual callback was dropped (e.g.
25 // due to connection error). This can save the burden of tracking pending
26 // mojo callbacks in a map so they can be cleaned up in the interface's
27 // connection error callback.
28 //
29 // Caveats:
30 // 1) The default form of the callback, called when the original was dropped
31 // before running, may not run on the thread you expected. If this is a problem
32 // for your code, DO NOT USE these helpers.
33 // 2) There is no type information that indicates the wrapped object has special
34 // destructor behavior.  It is therefore not recommended to pass these wrapped
35 // callbacks into deep call graphs where code readers could be confused whether
36 // or not the Run() mehtod should be invoked.
37 //
38 // Example:
39 //   foo->DoWorkAndReturnResult(
40 //       WrapCallbackWithDefaultInvokeIfNotRun(
41 //           base::BindOnce(&Foo::OnResult, this), false));
42 //
43 // If the callback is destructed without running, it'll be run with "false".
44 //
45 //  foo->DoWorkAndReturnResult(
46 //      WrapCallbackWithDropHandler(base::BindOnce(&Foo::OnResult, this),
47 //                         base::BindOnce(&Foo::LogError, this, WAS_DROPPED)));
48 
49 namespace mojo {
50 namespace internal {
51 
52 // First, tell the compiler CallbackWithDeleteHelper is a class template with
53 // one type parameter. Then define specializations where the type is a function
54 // returning void and taking zero or more arguments.
55 template <typename Signature>
56 class CallbackWithDeleteHelper;
57 
58 // Only support callbacks that return void because otherwise it is odd to call
59 // the callback in the destructor and drop the return value immediately.
60 template <typename... Args>
61 class CallbackWithDeleteHelper<void(Args...)> {
62  public:
63   using CallbackType = base::OnceCallback<void(Args...)>;
64 
65   // Bound arguments may be different to the callback signature when wrappers
66   // are used, e.g. in base::Owned and base::Unretained case, they are
67   // OwnedWrapper and UnretainedWrapper. Use BoundArgs to help handle this.
68   template <typename... BoundArgs>
CallbackWithDeleteHelper(CallbackType callback,BoundArgs &&...args)69   explicit CallbackWithDeleteHelper(CallbackType callback, BoundArgs&&... args)
70       : callback_(std::move(callback)) {
71     delete_callback_ =
72         base::BindOnce(&CallbackWithDeleteHelper::Run, base::Unretained(this),
73                        std::forward<BoundArgs>(args)...);
74   }
75 
76   // The first int param acts to disambiguate this constructor from the template
77   // constructor above. The precendent is C++'s own operator++(int) vs
78   // operator++() to distinguish post-increment and pre-increment.
CallbackWithDeleteHelper(int ignored,CallbackType callback,base::OnceClosure delete_callback)79   CallbackWithDeleteHelper(int ignored,
80                            CallbackType callback,
81                            base::OnceClosure delete_callback)
82       : callback_(std::move(callback)),
83         delete_callback_(std::move(delete_callback)) {}
84 
~CallbackWithDeleteHelper()85   ~CallbackWithDeleteHelper() {
86     if (delete_callback_)
87       std::move(delete_callback_).Run();
88   }
89 
Run(Args...args)90   void Run(Args... args) {
91     delete_callback_.Reset();
92     std::move(callback_).Run(std::forward<Args>(args)...);
93   }
94 
95  private:
96   CallbackType callback_;
97   base::OnceClosure delete_callback_;
98 
99   DISALLOW_COPY_AND_ASSIGN(CallbackWithDeleteHelper);
100 };
101 
102 }  // namespace internal
103 
104 template <typename T, typename... Args>
WrapCallbackWithDropHandler(base::OnceCallback<T> cb,base::OnceClosure delete_cb)105 inline base::OnceCallback<T> WrapCallbackWithDropHandler(
106     base::OnceCallback<T> cb,
107     base::OnceClosure delete_cb) {
108   return base::BindOnce(&internal::CallbackWithDeleteHelper<T>::Run,
109                         std::make_unique<internal::CallbackWithDeleteHelper<T>>(
110                             0, std::move(cb), std::move(delete_cb)));
111 }
112 
113 template <typename T, typename... Args>
WrapCallbackWithDefaultInvokeIfNotRun(base::OnceCallback<T> cb,Args &&...args)114 inline base::OnceCallback<T> WrapCallbackWithDefaultInvokeIfNotRun(
115     base::OnceCallback<T> cb,
116     Args&&... args) {
117   return base::BindOnce(&internal::CallbackWithDeleteHelper<T>::Run,
118                         std::make_unique<internal::CallbackWithDeleteHelper<T>>(
119                             std::move(cb), std::forward<Args>(args)...));
120 }
121 
122 }  // namespace mojo
123 
124 #endif  // MOJO_PUBLIC_CPP_BINDINGS_CALLBACK_HELPERS_H_
125