// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef BASE_BIND_H_ #define BASE_BIND_H_ #include #include "base/bind_internal.h" // ----------------------------------------------------------------------------- // Usage documentation // ----------------------------------------------------------------------------- // // See //docs/callback.md for documentation. // // // ----------------------------------------------------------------------------- // Implementation notes // ----------------------------------------------------------------------------- // // If you're reading the implementation, before proceeding further, you should // read the top comment of base/bind_internal.h for a definition of common // terms and concepts. namespace base { namespace internal { // IsOnceCallback is a std::true_type if |T| is a OnceCallback. template struct IsOnceCallback : std::false_type {}; template struct IsOnceCallback> : std::true_type {}; // 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 struct AssertConstructible { private: static constexpr bool param_is_forwardable = std::is_constructible::value; // Unlike the check for binding into storage below, the check for // forwardability drops the const qualifier for repeating callbacks. This is // to try to catch instances where std::move()--which forwards as a const // reference with repeating callbacks--is used instead of base::Passed(). static_assert( param_is_forwardable || !std::is_constructible&&>::value, "Bound argument |i| is move-only but will be forwarded by copy. " "Ensure |Arg| is bound using base::Passed(), not std::move()."); static_assert( param_is_forwardable, "Bound argument |i| of type |Arg| cannot be forwarded as " "|Unwrapped| to the bound functor, which declares it as |Param|."); static constexpr bool arg_is_storable = std::is_constructible::value; static_assert(arg_is_storable || !std::is_constructible&&>::value, "Bound argument |i| is move-only but will be bound by copy. " "Ensure |Arg| is mutable and bound using std::move()."); static_assert(arg_is_storable, "Bound argument |i| of type |Arg| cannot be converted and " "bound as |Storage|."); }; // Takes three same-length TypeLists, and applies AssertConstructible for each // triples. template struct AssertBindArgsValidity; template struct AssertBindArgsValidity, TypeList, TypeList, TypeList> : AssertConstructible, Unwrapped, Params>... { static constexpr bool ok = true; }; // The implementation of TransformToUnwrappedType below. template struct TransformToUnwrappedTypeImpl; template struct TransformToUnwrappedTypeImpl { using StoredType = std::decay_t; using ForwardType = StoredType&&; using Unwrapped = decltype(Unwrap(std::declval())); }; template struct TransformToUnwrappedTypeImpl { using StoredType = std::decay_t; using ForwardType = const StoredType&; using Unwrapped = decltype(Unwrap(std::declval())); }; // Transform |T| into `Unwrapped` type, which is passed to the target function. // Example: // In is_once == true case, // `int&&` -> `int&&`, // `const int&` -> `int&&`, // `OwnedWrapper&` -> `int*&&`. // In is_once == false case, // `int&&` -> `const int&`, // `const int&` -> `const int&`, // `OwnedWrapper&` -> `int* const &`. template using TransformToUnwrappedType = typename TransformToUnwrappedTypeImpl::Unwrapped; // 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 struct MakeUnwrappedTypeListImpl { using Type = TypeList...>; }; // Performs special handling for this pointers. // Example: // int* -> int*, // std::unique_ptr -> int*. template struct MakeUnwrappedTypeListImpl { using UnwrappedReceiver = TransformToUnwrappedType; using Type = TypeList()), TransformToUnwrappedType...>; }; template using MakeUnwrappedTypeList = typename MakeUnwrappedTypeListImpl::Type; } // namespace internal // Bind as OnceCallback. template inline OnceCallback> BindOnce(Functor&& functor, Args&&... args) { static_assert(!internal::IsOnceCallback>() || (std::is_rvalue_reference() && !std::is_const>()), "BindOnce requires non-const rvalue for OnceCallback binding." " I.e.: base::BindOnce(std::move(callback))."); // This block checks if each |args| matches to the corresponding params of the // target function. This check does not affect the behavior of Bind, but its // error message should be more readable. using Helper = internal::BindTypeHelper; using FunctorTraits = typename Helper::FunctorTraits; using BoundArgsList = typename Helper::BoundArgsList; using UnwrappedArgsList = internal::MakeUnwrappedTypeList; using BoundParamsList = typename Helper::BoundParamsList; static_assert(internal::AssertBindArgsValidity< std::make_index_sequence, BoundArgsList, UnwrappedArgsList, BoundParamsList>::ok, "The bound args need to be convertible to the target params."); using BindState = internal::MakeBindStateType; using UnboundRunType = MakeUnboundRunType; using Invoker = internal::Invoker; using CallbackType = OnceCallback; // Store the invoke func into PolymorphicInvoke before casting it to // InvokeFuncStorage, so that we can ensure its type matches to // PolymorphicInvoke, to which CallbackType will cast back. using PolymorphicInvoke = typename CallbackType::PolymorphicInvoke; PolymorphicInvoke invoke_func = &Invoker::RunOnce; using InvokeFuncStorage = internal::BindStateBase::InvokeFuncStorage; return CallbackType(new BindState( reinterpret_cast(invoke_func), std::forward(functor), std::forward(args)...)); } // Bind as RepeatingCallback. template inline RepeatingCallback> BindRepeating(Functor&& functor, Args&&... args) { static_assert( !internal::IsOnceCallback>(), "BindRepeating cannot bind OnceCallback. Use BindOnce with std::move()."); // This block checks if each |args| matches to the corresponding params of the // target function. This check does not affect the behavior of Bind, but its // error message should be more readable. using Helper = internal::BindTypeHelper; using FunctorTraits = typename Helper::FunctorTraits; using BoundArgsList = typename Helper::BoundArgsList; using UnwrappedArgsList = internal::MakeUnwrappedTypeList; using BoundParamsList = typename Helper::BoundParamsList; static_assert(internal::AssertBindArgsValidity< std::make_index_sequence, BoundArgsList, UnwrappedArgsList, BoundParamsList>::ok, "The bound args need to be convertible to the target params."); using BindState = internal::MakeBindStateType; using UnboundRunType = MakeUnboundRunType; using Invoker = internal::Invoker; using CallbackType = RepeatingCallback; // Store the invoke func into PolymorphicInvoke before casting it to // InvokeFuncStorage, so that we can ensure its type matches to // PolymorphicInvoke, to which CallbackType will cast back. using PolymorphicInvoke = typename CallbackType::PolymorphicInvoke; PolymorphicInvoke invoke_func = &Invoker::Run; using InvokeFuncStorage = internal::BindStateBase::InvokeFuncStorage; return CallbackType(new BindState( reinterpret_cast(invoke_func), std::forward(functor), std::forward(args)...)); } // Unannotated Bind. // TODO(tzik): Deprecate this and migrate to OnceCallback and // RepeatingCallback, once they get ready. template inline Callback> Bind(Functor&& functor, Args&&... args) { return BindRepeating(std::forward(functor), std::forward(args)...); } // Special cases for binding to a base::Callback without extra bound arguments. template OnceCallback BindOnce(OnceCallback closure) { return closure; } template RepeatingCallback BindRepeating( RepeatingCallback closure) { return closure; } template Callback Bind(Callback closure) { return closure; } } // namespace base #endif // BASE_BIND_H_