151 lines
5.8 KiB
C++
151 lines
5.8 KiB
C++
// Copyright 2022 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#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"
|
|
|
|
namespace base::internal {
|
|
|
|
// RectifyCallbackWrapper binds a wrapper around the actual callback that
|
|
// discards the ignored arguments and forwards the remaining arguments to the
|
|
// wrapped callback.
|
|
|
|
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 (IsOnceCallback<CallbackType<void()>>::value) {
|
|
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));
|
|
}
|
|
}
|
|
};
|
|
|
|
// RectifyCallbackSplitter is a helper that returns the first N args of
|
|
// `Signature` as the type `void(Args...)`. These are the arguments that need
|
|
// to be ignored when rectifying a 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)> {
|
|
};
|
|
|
|
// Given a desired type and an actual type, RectifyCallbackImpl provides a
|
|
// Rectify() method that adapts the input callback to be callable using the
|
|
// arguments from desired type.
|
|
|
|
template <typename DesiredType, typename ActualType, typename SFINAE = void>
|
|
struct RectifyCallbackImpl;
|
|
|
|
// Main specialization that handles the case where the desired and actual types
|
|
// have already been normalized into callback types. The other specializations
|
|
// allow additional flexibility for callers, but eventually all delegate here.
|
|
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...)>) {
|
|
// No adapting needed when the parameter lists already match.
|
|
return callback;
|
|
}
|
|
|
|
// For uniformity, if the input callback is null, the output callback should
|
|
// be null as well.
|
|
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));
|
|
}
|
|
};
|
|
|
|
// Specialization that handles a type signature as the desired type. The output
|
|
// in this case will be based on the type of callback passed in.
|
|
template <typename R,
|
|
typename... Args,
|
|
template <typename>
|
|
typename ActualCallbackType,
|
|
typename ActualSignature>
|
|
struct RectifyCallbackImpl<R(Args...), ActualCallbackType<ActualSignature>>
|
|
: RectifyCallbackImpl<ActualCallbackType<R(Args...)>,
|
|
ActualCallbackType<ActualSignature>> {};
|
|
|
|
// Fallback for things like DoNothing(), NullCallback(), etc. where a specific
|
|
// callback return type is provided.
|
|
template <template <typename> typename DesiredCallbackType,
|
|
typename R,
|
|
typename... Args,
|
|
typename T>
|
|
struct RectifyCallbackImpl<DesiredCallbackType<R(Args...)>,
|
|
T,
|
|
std::enable_if_t<!IsBaseCallback<T>::value>>
|
|
: RectifyCallbackImpl<DesiredCallbackType<R(Args...)>,
|
|
DesiredCallbackType<R(Args...)>> {};
|
|
|
|
// Fallback for things like DoNothing(), NullCallback(), etc. where only the
|
|
// signature of the return type is provided. In this case, `RepeatingCallback`
|
|
// is implicitly generated, as it can be used as both a `OnceCallback` or
|
|
// `RepeatingCallback`.
|
|
template <typename R, typename... Args, typename T>
|
|
struct RectifyCallbackImpl<R(Args...), T>
|
|
: RectifyCallbackImpl<RepeatingCallback<R(Args...)>,
|
|
RepeatingCallback<R(Args...)>> {};
|
|
|
|
} // namespace base::internal
|
|
|
|
#endif // BASE_TEST_RECTIFY_CALLBACK_INTERNAL_H_
|