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