chromium/base/functional/bind_internal.h

// Copyright 2011 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_FUNCTIONAL_BIND_INTERNAL_H_
#define BASE_FUNCTIONAL_BIND_INTERNAL_H_

#include <stddef.h>

#include <concepts>
#include <functional>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>

#include "base/check.h"
#include "base/compiler_specific.h"
#include "base/functional/callback_internal.h"
#include "base/functional/unretained_traits.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ptr_asan_bound_arg_tracker.h"
#include "base/memory/raw_ref.h"
#include "base/memory/raw_scoped_refptr_mismatch_checker.h"
#include "base/memory/weak_ptr.h"
#include "base/notreached.h"
#include "base/types/always_false.h"
#include "base/types/is_complete.h"
#include "base/types/is_instantiation.h"
#include "base/types/to_address.h"
#include "build/build_config.h"
#include "partition_alloc/buildflags.h"
#include "partition_alloc/partition_alloc_config.h"
#include "third_party/abseil-cpp/absl/functional/function_ref.h"

// See docs/callback.md for user documentation.
//
// Concepts:
//  Functor -- A movable type representing something that should be called.
//             All function pointers and `Callback<>` are functors even if the
//             invocation syntax differs.
//  RunType -- A function type (as opposed to function _pointer_ type) for
//             a `Callback<>::Run()`.  Usually just a convenience typedef.
//  (Bound)Args -- A set of types that stores the arguments.
//
// Types:
//  `ForceVoidReturn<>` -- Helper class for translating function signatures to
//                         equivalent forms with a `void` return type.
//  `FunctorTraits<>` -- Type traits used to determine the correct RunType and
//                       invocation manner for a Functor.  This is where
//                       function signature adapters are applied.
//  `StorageTraits<>` -- Type traits that determine how a bound argument is
//                       stored in `BindState<>`.
//  `InvokeHelper<>` -- Takes a Functor + arguments and actually invokes it.
//                      Handles the differing syntaxes needed for `WeakPtr<>`
//                      support.  This is separate from `Invoker<>` to avoid
//                      creating multiple versions of `Invoker<>`.
//  `Invoker<>` -- Unwraps the curried parameters and executes the Functor.
//  `BindState<>` -- Stores the curried parameters, and is the main entry point
//                   into the `Bind()` system.

#if BUILDFLAG(IS_WIN)
namespace Microsoft {
namespace WRL {
template <typename>
class ComPtr;
}  // namespace WRL
}  // namespace Microsoft
#endif

namespace base {

template <typename T>
struct IsWeakReceiver;

template <typename>
struct BindUnwrapTraits;

template <typename Functor, typename BoundArgsTuple>
struct CallbackCancellationTraits;

template <typename Signature>
class FunctionRef;

// A tag type to return when `Bind()` calls fail. In this case we intentionally
// don't return `void`, since that would produce spurious errors like "variable
// has incomplete type 'void'" when assigning the result of
// `Bind{Once,Repeating}()` to an `auto`.
struct BindFailedCheckPreviousErrors {};

namespace unretained_traits {

// `UnretainedWrapper` will check and report if pointer is dangling upon
// invocation.
struct MayNotDangle {};
// `UnretainedWrapper` won't check if pointer is dangling upon invocation. For
// extra safety, the receiver must be of type `MayBeDangling<>`.
struct MayDangle {};
// `UnretainedWrapper` won't check if pointer is dangling upon invocation. The
// receiver doesn't have to be a `raw_ptr<>`. This is just a temporary state, to
// allow dangling pointers that would otherwise crash if `MayNotDangle` was
// used. It should be replaced ASAP with `MayNotDangle` (after fixing the
// dangling pointers) or with `MayDangle` if there is really no other way (after
// making receivers `MayBeDangling<>`).
struct MayDangleUntriaged {};

}  // namespace unretained_traits

namespace internal {

template <typename T,
          typename UnretainedTrait,
          RawPtrTraits PtrTraits = RawPtrTraits::kEmpty>
class UnretainedWrapper {};

// Storage type for `std::reference_wrapper` so `BindState` can internally store
// unprotected references using `raw_ref`.
//
// `std::reference_wrapper<T>` and `T&` do not work, since the reference
// lifetime is not safely protected by MiraclePtr.
//
// `UnretainedWrapper<T>` and `raw_ptr<T>` do not work, since `BindUnwrapTraits`
// would try to pass by `T*` rather than `T&`.
template <typename T,
          typename UnretainedTrait,
          RawPtrTraits PtrTraits = RawPtrTraits::kEmpty>
class UnretainedRefWrapper {};

// Can't use `is_instantiation` to detect the unretained wrappers, since they
// have non-type template params.
kIsUnretainedWrapper;

kIsUnretainedWrapper;

// The class is used to wrap `UnretainedRefWrapper` when the latter is used as
// a method receiver (a reference on `this` argument). This is needed because
// the internal callback mechanism expects the receiver to have the type
// `MyClass*` and to have `operator*`.
// This is used as storage.
template <typename T, typename UnretainedTrait, RawPtrTraits PtrTraits>
class UnretainedRefWrapperReceiver {};

// `MethodReceiverStorage` converts the current receiver type to its stored
// type. For instance, it converts pointers to `scoped_refptr`, and wraps
// `UnretainedRefWrapper` to make it compliant with the internal callback
// invocation mechanism.
template <typename T>
struct MethodReceiverStorage {};

MethodReceiverStorage<UnretainedRefWrapper<T, UnretainedTrait, PtrTraits>>;

template <typename T>
class RetainedRefWrapper {};

template <typename T>
struct IgnoreResultHelper {};

template <typename T, typename Deleter = std::default_delete<T>>
class OwnedWrapper {
 public:
  explicit OwnedWrapper(T* o) :{}
  explicit OwnedWrapper(std::unique_ptr<T, Deleter>&& ptr)
      :{}
  T* get() const {}

 private:
  std::unique_ptr<T, Deleter> ptr_;
};

template <typename T>
class OwnedRefWrapper {};

// `PassedWrapper` is a copyable adapter for a scoper that ignores `const`.
//
// It is needed to get around the fact that `Bind()` takes a const reference to
// all its arguments.  Because `Bind()` takes a const reference to avoid
// unnecessary copies, it is incompatible with movable-but-not-copyable
// types; doing a destructive "move" of the type into `Bind()` would violate
// the const correctness.
//
// This conundrum cannot be solved without either rvalue references or an O(2^n)
// blowup of `Bind()` templates to handle each combination of regular types and
// movable-but-not-copyable types.  Thus we introduce a wrapper type that is
// copyable to transmit the correct type information down into `BindState<>`.
// Ignoring `const` in this type makes sense because it is only created when we
// are explicitly trying to do a destructive move.
//
// Two notes:
//  1) `PassedWrapper` supports any type that has a move constructor, however
//     the type will need to be specifically allowed in order for it to be
//     bound to a `Callback`. We guard this explicitly at the call of `Passed()`
//     to make for clear errors. Things not given to `Passed()` will be
//     forwarded and stored by value which will not work for general move-only
//     types.
//  2) `is_valid_` is distinct from `nullptr` because it is valid to bind a null
//     scoper to a `Callback` and allow the `Callback` to execute once.
//
// TODO(crbug.com/40840557): We have rvalue references and such now. Remove.
template <typename T>
class PassedWrapper {};

Unwrapper;

template <typename T>
decltype(auto) Unwrap(T&& o) {}

// `kIsWeakMethod` is a helper that determines if we are binding a `WeakPtr<>`
// to a method. It is used internally by `Bind()` to select the correct
// `InvokeHelper` that will no-op itself in the event the `WeakPtr<>` for the
// target object is invalidated.
//
// The first argument should be the type of the object that will be received by
// the method.
kIsWeakMethod;

kIsWeakMethod;

// Packs a list of types to hold them in a single type.
template <typename... Types>
struct TypeList {};

// Implements `DropTypeListItem`.
template <size_t n, typename List>
  requires is_instantiation<TypeList, List>
struct DropTypeListItemImpl {};

DropTypeListItemImpl<n, TypeList<T, List...>>;

// A type-level function that drops `n` list items from a given `TypeList`.
DropTypeListItem;

// Implements `TakeTypeListItem`.
template <size_t n, typename List, typename... Accum>
  requires is_instantiation<TypeList, List>
struct TakeTypeListItemImpl {};

TakeTypeListItemImpl<n, TypeList<T, List...>, Accum...>;

// A type-level function that takes the first `n` items from a given `TypeList`;
// e.g. `TakeTypeListItem<3, TypeList<A, B, C, D>>` -> `TypeList<A, B, C>`.
TakeTypeListItem;

// Implements `MakeFunctionType`.
template <typename R, typename ArgList>
struct MakeFunctionTypeImpl;

MakeFunctionTypeImpl<R, TypeList<Args...>>;

// A type-level function that constructs a function type that has `R` as its
// return type and has a `TypeList`'s items as its arguments.
MakeFunctionType;

// Implements `ExtractArgs` and `ExtractReturnType`.
template <typename Signature>
struct ExtractArgsImpl;

ExtractArgsImpl<R (Args...)>;

// A type-level function that extracts function arguments into a `TypeList`;
// e.g. `ExtractArgs<R(A, B, C)>` -> `TypeList<A, B, C>`.
ExtractArgs;

// A type-level function that extracts the return type of a function.
// e.g. `ExtractReturnType<R(A, B, C)>` -> `R`.
ExtractReturnType;

template <typename Callable,
          typename Signature = decltype(&Callable::operator())>
struct ExtractCallableRunTypeImpl;

#define BIND_INTERNAL_EXTRACT_CALLABLE_RUN_TYPE_WITH_QUALS

BIND_INTERNAL_EXTRACT_CALLABLE_RUN_TYPE_WITH_QUALS;
BIND_INTERNAL_EXTRACT_CALLABLE_RUN_TYPE_WITH_QUALS;
BIND_INTERNAL_EXTRACT_CALLABLE_RUN_TYPE_WITH_QUALS;
BIND_INTERNAL_EXTRACT_CALLABLE_RUN_TYPE_WITH_QUALS;

#undef BIND_INTERNAL_EXTRACT_CALLABLE_RUN_TYPE_WITH_QUALS

// Evaluated to the RunType of the given callable type; e.g.
// `ExtractCallableRunType<decltype([](int, char*) { return 0.1; })>` ->
//     `double(int, char*)`.
ExtractCallableRunType;

// True when `Functor` has a non-overloaded `operator()()`, e.g.:
//   struct S1 {
//     int operator()(int);
//   };
//   static_assert(HasNonOverloadedCallOp<S1>);
//
//   int i = 0;
//   auto f = [i] {};
//   static_assert(HasNonOverloadedCallOp<decltype(f)>);
//
//   struct S2 {
//     int operator()(int);
//     std::string operator()(std::string);
//   };
//   static_assert(!HasNonOverloadedCallOp<S2>);
//
//   static_assert(!HasNonOverloadedCallOp<void(*)()>);
//
//   struct S3 {};
//   static_assert(!HasNonOverloadedCallOp<S3>);
// ```
HasNonOverloadedCallOp;

IsObjCArcBlockPointer;

#if __OBJC__ && HAS_FEATURE(objc_arc)
template <typename R, typename... Args>
inline constexpr bool IsObjCArcBlockPointer<R (^)(Args...)> = true;
#endif

// True when `Functor` has an overloaded `operator()()` that can be invoked with
// the provided `BoundArgs`.
//
// Do not decay `Functor` before testing this, lest it give an incorrect result
// for overloads with different ref-qualifiers.
HasOverloadedCallOp;

// `HasRefCountedTypeAsRawPtr` is true when any of the `Args` is a raw pointer
// to a `RefCounted` type.
HasRefCountedTypeAsRawPtr;

// `ForceVoidReturn<>` converts a signature to have a `void` return type.
template <typename Sig>
struct ForceVoidReturn;

ForceVoidReturn<R (Args...)>;

// `FunctorTraits<>`
//
// See description at top of file. This must be declared here so it can be
// referenced in `DecayedFunctorTraits`.
template <typename Functor, typename... BoundArgs>
struct FunctorTraits;

// Provides functor traits for pre-decayed functor types.
template <typename Functor, typename... BoundArgs>
struct DecayedFunctorTraits;

// Callable types.
// This specialization handles lambdas (captureless and capturing) and functors
// with a call operator. Capturing lambdas and stateful functors are explicitly
// disallowed by `BindHelper<>::Bind()`; e.g.:
// ```
//   // Captureless lambda: Allowed
//   [] { return 42; };
//
//   // Capturing lambda: Disallowed
//   int x;
//   [x] { return x; };
//
//   // Empty class with `operator()()`: Allowed
//   struct Foo {
//     void operator()() const {}
//     // No non-`static` member variables and no virtual functions.
//   };
// ```
DecayedFunctorTraits<Functor, BoundArgs...>;

// Functions.
DecayedFunctorTraits<R (*)(Args...), BoundArgs...>;

DecayedFunctorTraits<R (*)(Args...) noexcept, BoundArgs...>;

#if BUILDFLAG(IS_WIN) && !defined(ARCH_CPU_64_BITS)

// `__stdcall` and `__fastcall` functions.
#define BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_WITH_CONV_AND_QUALS

BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_WITH_CONV_AND_QUALS(__stdcall, );
BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_WITH_CONV_AND_QUALS(__stdcall, noexcept);
BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_WITH_CONV_AND_QUALS(__fastcall, );
BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_WITH_CONV_AND_QUALS(__fastcall, noexcept);

#undef BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_WITH_CONV_AND_QUALS
#endif  // BUILDFLAG(IS_WIN) && !defined(ARCH_CPU_64_BITS)

#if __OBJC__ && HAS_FEATURE(objc_arc)

// Objective-C blocks. Blocks can be bound as the compiler will ensure their
// lifetimes will be correctly managed.
template <typename R, typename... Args, typename... BoundArgs>
struct DecayedFunctorTraits<R (^)(Args...), BoundArgs...> {
  using RunType = R(Args...);
  static constexpr bool is_method = false;
  static constexpr bool is_nullable = true;
  static constexpr bool is_callback = false;
  static constexpr bool is_stateless = true;

  template <typename BlockType, typename... RunArgs>
  static R Invoke(BlockType&& block, RunArgs&&... args) {
    // According to LLVM documentation (§ 6.3), "local variables of automatic
    // storage duration do not have precise lifetime." Use
    // `objc_precise_lifetime` to ensure that the Objective-C block is not
    // deallocated until it has finished executing even if the `Callback<>` is
    // destroyed during the block execution.
    // https://clang.llvm.org/docs/AutomaticReferenceCounting.html#precise-lifetime-semantics
    __attribute__((objc_precise_lifetime)) R (^scoped_block)(Args...) = block;
    return scoped_block(std::forward<RunArgs>(args)...);
  }
};

#endif  // __OBJC__ && HAS_FEATURE(objc_arc)

// Methods.
DecayedFunctorTraits<R (Receiver::*)(Args...), BoundArgs...>;

DecayedFunctorTraits<R (Receiver::*)(Args...) const, BoundArgs...>;

#define BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_WITH_CONST_AND_QUALS

BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_WITH_CONST_AND_QUALS;
BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_WITH_CONST_AND_QUALS;

#undef BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_WITH_CONST_AND_QUALS

#if BUILDFLAG(IS_WIN) && !defined(ARCH_CPU_64_BITS)

// `__stdcall` methods.
#define BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_STDCALL_WITH_QUALS

BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_STDCALL_WITH_QUALS();
BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_STDCALL_WITH_QUALS(const);
BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_STDCALL_WITH_QUALS(noexcept);
BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_STDCALL_WITH_QUALS(const noexcept);

#undef BIND_INTERNAL_DECAYED_FUNCTOR_TRAITS_STDCALL_WITH_QUALS

#endif  // BUILDFLAG(IS_WIN) && !defined(ARCH_CPU_64_BITS)

// `IgnoreResult`s.
DecayedFunctorTraits<IgnoreResultHelper<T>, BoundArgs...>;

// `OnceCallback`s.
DecayedFunctorTraits<OnceCallback<R (Args...)>, BoundArgs...>;

// `RepeatingCallback`s.
DecayedFunctorTraits<RepeatingCallback<R (Args...)>, BoundArgs...>;

// For most functors, the traits should not depend on how the functor is passed,
// so decay the functor.
FunctorTraits<Functor, BoundArgs...>;

// For `overloaded operator()()`s, it's possible the ref qualifiers of the
// functor matter, so be careful to use the undecayed type.
FunctorTraits<Functor, BoundArgs...>;

// `StorageTraits<>`
//
// See description at top of file.
template <typename T>
struct StorageTraits {};

// For `T*`, store as `UnretainedWrapper<T>` for safety, as it internally uses
// `raw_ptr<T>` (when possible).
StorageTraits<T *>;

// For `raw_ptr<T>`, store as `UnretainedWrapper<T>` for safety. This may seem
// contradictory, but this ensures guaranteed protection for the pointer even
// during execution of callbacks with parameters of type `raw_ptr<T>`.
StorageTraits<raw_ptr<T, PtrTraits>>;

// Unwrap `std::reference_wrapper` and store it in a custom wrapper so that
// references are also protected with `raw_ptr<T>`.
StorageTraits<std::reference_wrapper<T>>;

ValidateStorageTraits;

// `InvokeHelper<>`
//
// There are 2 logical `InvokeHelper<>` specializations: normal, weak.
//
// The normal type just calls the underlying runnable.
//
// Weak calls need special syntax that is applied to the first argument to check
// if they should no-op themselves.
template <bool is_weak_call,
          typename Traits,
          typename ReturnType,
          size_t... indices>
struct InvokeHelper;

InvokeHelper<false, Traits, ReturnType, indices...>;

InvokeHelper<true, Traits, ReturnType, index_target, index_tail...>;

// `Invoker<>`
//
// See description at the top of the file.
template <typename Traits, typename StorageType, typename UnboundRunType>
struct Invoker;

Invoker<Traits, StorageType, R (UnboundArgs...)>;

// Allow binding a method call with no receiver.
// TODO(crbug.com/41484339): Remove or make safe.
template <typename... Unused>
void VerifyMethodReceiver(Unused&&...) {}

template <typename Receiver, typename... Unused>
void VerifyMethodReceiver(Receiver&& receiver, Unused&&...) {}

// `BindState<>`
//
// This stores all the state passed into `Bind()`.
template <bool is_method,
          bool is_nullable,
          bool is_callback,
          typename Functor,
          typename... BoundArgs>
struct BindState final : BindStateBase {};

// Used to determine and validate the appropriate `BindState`. The
// specializations below cover all cases. The members are similar in intent to
// those in `StorageTraits`; see comments there.
template <bool is_method,
          bool is_nullable,
          bool is_callback,
          typename Functor,
          typename... BoundArgs>
struct ValidateBindStateType;

ValidateBindStateType<false, is_nullable, is_callback, Functor, BoundArgs...>;

ValidateBindStateType<true, is_nullable, is_callback, Functor>;

ValidateBindStateType<true, is_nullable, is_callback, Functor, Receiver, BoundArgs...>;

// Transforms `T` into an unwrapped type, which is passed to the target
// function; e.g.:
// * `is_once` cases:
// ** `TransformToUnwrappedType<true, int&&>` -> `int&&`
// ** `TransformToUnwrappedType<true, const int&>` -> `int&&`
// ** `TransformToUnwrappedType<true, OwnedWrapper<int>&>` -> `int*&&`
// * `!is_once` cases:
// ** `TransformToUnwrappedType<false, int&&>` -> `const int&`
// ** `TransformToUnwrappedType<false, const int&>` -> `const int&`
// ** `TransformToUnwrappedType<false, OwnedWrapper<int>&>` -> `int* const &`
TransformToUnwrappedType;

// Used to convert `this` arguments to underlying pointer types; e.g.:
//   `int*` -> `int*`
//   `std::unique_ptr<int>` -> `int*`
//   `int` -> (assertion failure; `this` must be a pointer-like object)
template <typename T>
struct ValidateReceiverType {};

ValidateReceiverType<T>;

// Transforms `Args` into unwrapped types, and packs them into a `TypeList`. If
// `is_method` is true, tries to dereference the first argument to support smart
// pointers.
template <bool is_once, bool is_method, typename... Args>
struct ValidateUnwrappedTypeList {};

ValidateUnwrappedTypeList<is_once, true, Receiver, Args...>;

// `IsUnretainedMayDangle` is true iff `StorageType` is marked with
// `unretained_traits::MayDangle`. Note that it is false for
// `unretained_traits::MayDangleUntriaged`.
IsUnretainedMayDangle;

IsUnretainedMayDangle;

// `UnretainedAndRawPtrHaveCompatibleTraits` is true iff `StorageType` is marked
// with `unretained_traits::MayDangle`, `FunctionParamType` is a `raw_ptr`, and
// `StorageType::GetPtrType` is the same type as `FunctionParamType`.
UnretainedAndRawPtrHaveCompatibleTraits;

UnretainedAndRawPtrHaveCompatibleTraits;

// Helpers to make error messages slightly more readable.
template <int i>
struct BindArgument {};

// Helper to assert that parameter `i` of type `Arg` can be bound, which means:
// * `Arg` can be retained internally as `Storage`
// * `Arg` can be forwarded as `Unwrapped` to `Param`
template <int i,
          bool is_method,
          typename Arg,
          typename Storage,
          typename Unwrapped,
          typename Param>
struct ParamCanBeBound {};

// Takes three same-length `TypeList`s, and checks `ParamCanBeBound` for each
// triple.
template <bool is_method,
          typename Index,
          typename Args,
          typename UnwrappedTypeList,
          typename ParamsList>
struct ParamsCanBeBound {};

ParamsCanBeBound<is_method, std::index_sequence<Ns...>, TypeList<Args...>, TypeList<UnwrappedTypes...>, TypeList<Params...>>;

// Core implementation of `Bind()`, which checks common preconditions before
// returning an appropriate callback.
template <template <typename> class CallbackT>
struct BindHelper {};

}  // namespace internal

// An injection point to control `this` pointer behavior on a method invocation.
// If `IsWeakReceiver<T>::value` is `true` and `T` is used as a method receiver,
// `Bind()` cancels the method invocation if the receiver tests as false.
// ```
//   struct S : SupportsWeakPtr<S> {
//     void f() {}
//   };
//
//   WeakPtr<S> weak_s = nullptr;
//   BindOnce(&S::f, weak_s).Run();  // `S::f()` is not called.
// ```
template <typename T>
struct IsWeakReceiver : std::bool_constant<is_instantiation<WeakPtr, T>> {};

IsWeakReceiver<std::reference_wrapper<T>>;

// An injection point to control how objects are checked for maybe validity,
// which is an optimistic thread-safe check for full validity.
template <typename>
struct MaybeValidTraits {};

// An injection point to control how bound objects passed to the target
// function. `BindUnwrapTraits<>::Unwrap()` is called for each bound object
// right before the target function is invoked.
template <typename>
struct BindUnwrapTraits {};

BindUnwrapTraits<T>;

BindUnwrapTraits<internal::PassedWrapper<T>>;

#if BUILDFLAG(IS_WIN)
template <typename T>
struct BindUnwrapTraits<Microsoft::WRL::ComPtr<T>> {
  static T* Unwrap(const Microsoft::WRL::ComPtr<T>& ptr) { return ptr.Get(); }
};
#endif

// `CallbackCancellationTraits` allows customization of `Callback`'s
// cancellation semantics. By default, callbacks are not cancellable. A
// specialization should set `is_cancellable` and implement an `IsCancelled()`
// that returns whether the callback should be cancelled, as well as a
// `MaybeValid()` that returns whether the underlying functor/object is maybe
// valid.
template <typename Functor, typename BoundArgsTuple>
struct CallbackCancellationTraits {};

// Specialization for a weak receiver.
CallbackCancellationTraits<Functor, std::tuple<BoundArgs...>>;

// Specialization for a nested `Bind()`.
CallbackCancellationTraits<Functor, std::tuple<BoundArgs...>>;

}  // namespace base

#endif  // BASE_FUNCTIONAL_BIND_INTERNAL_H_