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