• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 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 #ifndef BASE_TEST_RECTIFY_CALLBACK_INTERNAL_H_
6 #define BASE_TEST_RECTIFY_CALLBACK_INTERNAL_H_
7 
8 #include <utility>
9 
10 #include "base/functional/bind.h"
11 #include "base/functional/callback.h"
12 #include "base/functional/callback_helpers.h"
13 
14 namespace base::internal {
15 
16 // RectifyCallbackWrapper binds a wrapper around the actual callback that
17 // discards the ignored arguments and forwards the remaining arguments to the
18 // wrapped callback.
19 
20 template <template <typename> typename CallbackType,
21           typename PartialSignature,
22           typename IgnoreSignature>
23 struct RectifyCallbackWrapper;
24 
25 template <template <typename> typename CallbackType,
26           typename R,
27           typename... PartialArgs,
28           typename... IgnoredArgs>
29 struct RectifyCallbackWrapper<CallbackType,
30                               R(PartialArgs...),
31                               void(IgnoredArgs...)> {
32   template <typename Actual>
33   static CallbackType<R(IgnoredArgs..., PartialArgs...)> Rectify(
34       Actual&& callback) {
35     if constexpr (IsOnceCallback<CallbackType<void()>>::value) {
36       return BindOnce(
37           [](OnceCallback<R(PartialArgs...)> callback, IgnoredArgs...,
38              PartialArgs... args) {
39             return std::move(callback).Run(std::forward<PartialArgs>(args)...);
40           },
41           std::forward<Actual>(callback));
42     } else {
43       return BindRepeating(
44           [](const RepeatingCallback<R(PartialArgs...)> callback,
45              IgnoredArgs..., PartialArgs... args) {
46             return callback.Run(std::forward<PartialArgs>(args)...);
47           },
48           std::forward<Actual>(callback));
49     }
50   }
51 };
52 
53 // RectifyCallbackSplitter is a helper that returns the first N args of
54 // `Signature` as the type `void(Args...)`. These are the arguments that need
55 // to be ignored when rectifying a callback.
56 
57 template <size_t count, typename Signature, typename Result = void()>
58 struct RectifyCallbackSplitter;
59 
60 template <typename Arg, typename... Args, typename... Results>
61 struct RectifyCallbackSplitter<0, void(Arg, Args...), void(Results...)> {
62   using type = void(Results...);
63 };
64 
65 template <typename... Args, typename... Results>
66 struct RectifyCallbackSplitter<0, void(Args...), void(Results...)> {
67   using type = void(Results...);
68 };
69 
70 template <size_t count, typename Arg, typename... Args, typename... Results>
71 struct RectifyCallbackSplitter<count, void(Arg, Args...), void(Results...)>
72     : RectifyCallbackSplitter<count - 1, void(Args...), void(Results..., Arg)> {
73 };
74 
75 // Given a desired type and an actual type, RectifyCallbackImpl provides a
76 // Rectify() method that adapts the input callback to be callable using the
77 // arguments from desired type.
78 
79 template <typename DesiredType, typename ActualType, typename SFINAE = void>
80 struct RectifyCallbackImpl;
81 
82 // Main specialization that handles the case where the desired and actual types
83 // have already been normalized into callback types. The other specializations
84 // allow additional flexibility for callers, but eventually all delegate here.
85 template <template <typename> typename DesiredCallbackType,
86           template <typename>
87           typename ActualCallbackType,
88           typename R,
89           typename... DesiredArgs,
90           typename... ActualArgs>
91 struct RectifyCallbackImpl<DesiredCallbackType<R(DesiredArgs...)>,
92                            ActualCallbackType<R(ActualArgs...)>> {
93   static DesiredCallbackType<R(DesiredArgs...)> Rectify(
94       ActualCallbackType<R(ActualArgs...)> callback) {
95     if constexpr (std::is_same_v<R(DesiredArgs...), R(ActualArgs...)>) {
96       // No adapting needed when the parameter lists already match.
97       return callback;
98     }
99 
100     // For uniformity, if the input callback is null, the output callback should
101     // be null as well.
102     if (!callback) {
103       return NullCallback();
104     }
105 
106     using IgnoreSignature =
107         typename RectifyCallbackSplitter<sizeof...(DesiredArgs) -
108                                              sizeof...(ActualArgs),
109                                          void(DesiredArgs...)>::type;
110     return RectifyCallbackWrapper<
111         DesiredCallbackType, R(ActualArgs...),
112         IgnoreSignature>::Rectify(std::move(callback));
113   }
114 };
115 
116 // Specialization that handles a type signature as the desired type. The output
117 // in this case will be based on the type of callback passed in.
118 template <typename R,
119           typename... Args,
120           template <typename>
121           typename ActualCallbackType,
122           typename ActualSignature>
123 struct RectifyCallbackImpl<R(Args...), ActualCallbackType<ActualSignature>>
124     : RectifyCallbackImpl<ActualCallbackType<R(Args...)>,
125                           ActualCallbackType<ActualSignature>> {};
126 
127 // Fallback for things like DoNothing(), NullCallback(), etc. where a specific
128 // callback return type is provided.
129 template <template <typename> typename DesiredCallbackType,
130           typename R,
131           typename... Args,
132           typename T>
133 struct RectifyCallbackImpl<DesiredCallbackType<R(Args...)>,
134                            T,
135                            std::enable_if_t<!IsBaseCallback<T>::value>>
136     : RectifyCallbackImpl<DesiredCallbackType<R(Args...)>,
137                           DesiredCallbackType<R(Args...)>> {};
138 
139 // Fallback for things like DoNothing(), NullCallback(), etc. where only the
140 // signature of the return type is provided. In this case, `RepeatingCallback`
141 // is implicitly generated, as it can be used as both a `OnceCallback` or
142 // `RepeatingCallback`.
143 template <typename R, typename... Args, typename T>
144 struct RectifyCallbackImpl<R(Args...), T>
145     : RectifyCallbackImpl<RepeatingCallback<R(Args...)>,
146                           RepeatingCallback<R(Args...)>> {};
147 
148 }  // namespace base::internal
149 
150 #endif  // BASE_TEST_RECTIFY_CALLBACK_INTERNAL_H_
151