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