#ifndef BASE_TEST_RECTIFY_CALLBACK_INTERNAL_H_
#define BASE_TEST_RECTIFY_CALLBACK_INTERNAL_H_
#include <utility>
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/types/is_instantiation.h"
namespace base::internal {
template <template <typename> typename CallbackType,
typename PartialSignature,
typename IgnoreSignature>
struct RectifyCallbackWrapper;
template <template <typename> typename CallbackType,
typename R,
typename... PartialArgs,
typename... IgnoredArgs>
struct RectifyCallbackWrapper<CallbackType,
R(PartialArgs...),
void(IgnoredArgs...)> {
template <typename Actual>
static CallbackType<R(IgnoredArgs..., PartialArgs...)> Rectify(
Actual&& callback) {
if constexpr (is_instantiation<CallbackType<void()>, OnceCallback>) {
return BindOnce(
[](OnceCallback<R(PartialArgs...)> callback, IgnoredArgs...,
PartialArgs... args) {
return std::move(callback).Run(std::forward<PartialArgs>(args)...);
},
std::forward<Actual>(callback));
} else {
return BindRepeating(
[](const RepeatingCallback<R(PartialArgs...)> callback,
IgnoredArgs..., PartialArgs... args) {
return callback.Run(std::forward<PartialArgs>(args)...);
},
std::forward<Actual>(callback));
}
}
};
template <size_t count, typename Signature, typename Result = void()>
struct RectifyCallbackSplitter;
template <typename Arg, typename... Args, typename... Results>
struct RectifyCallbackSplitter<0, void(Arg, Args...), void(Results...)> {
using type = void(Results...);
};
template <typename... Args, typename... Results>
struct RectifyCallbackSplitter<0, void(Args...), void(Results...)> {
using type = void(Results...);
};
template <size_t count, typename Arg, typename... Args, typename... Results>
struct RectifyCallbackSplitter<count, void(Arg, Args...), void(Results...)>
: RectifyCallbackSplitter<count - 1, void(Args...), void(Results..., Arg)> {
};
template <typename DesiredType, typename ActualType, typename SFINAE = void>
struct RectifyCallbackImpl;
template <template <typename> typename DesiredCallbackType,
template <typename>
typename ActualCallbackType,
typename R,
typename... DesiredArgs,
typename... ActualArgs>
struct RectifyCallbackImpl<DesiredCallbackType<R(DesiredArgs...)>,
ActualCallbackType<R(ActualArgs...)>> {
static DesiredCallbackType<R(DesiredArgs...)> Rectify(
ActualCallbackType<R(ActualArgs...)> callback) {
if constexpr (std::is_same_v<R(DesiredArgs...), R(ActualArgs...)>) {
return callback;
}
if (!callback) {
return NullCallback();
}
using IgnoreSignature =
typename RectifyCallbackSplitter<sizeof...(DesiredArgs) -
sizeof...(ActualArgs),
void(DesiredArgs...)>::type;
return RectifyCallbackWrapper<
DesiredCallbackType, R(ActualArgs...),
IgnoreSignature>::Rectify(std::move(callback));
}
};
template <typename R,
typename... Args,
template <typename>
typename ActualCallbackType,
typename ActualSignature>
struct RectifyCallbackImpl<R(Args...), ActualCallbackType<ActualSignature>>
: RectifyCallbackImpl<ActualCallbackType<R(Args...)>,
ActualCallbackType<ActualSignature>> {};
template <template <typename> typename DesiredCallbackType,
typename R,
typename... Args,
typename T>
struct RectifyCallbackImpl<DesiredCallbackType<R(Args...)>, T>
: RectifyCallbackImpl<DesiredCallbackType<R(Args...)>,
DesiredCallbackType<R(Args...)>> {};
template <typename R, typename... Args, typename T>
struct RectifyCallbackImpl<R(Args...), T>
: RectifyCallbackImpl<RepeatingCallback<R(Args...)>,
RepeatingCallback<R(Args...)>> {};
}
#endif