thrift/lib/cpp2/Thrift.h (257 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef THRIFT_CPP2_H_ #define THRIFT_CPP2_H_ #include <thrift/lib/cpp/FieldId.h> #include <thrift/lib/cpp/Thrift.h> #include <thrift/lib/cpp2/TypeClass.h> #include <initializer_list> #include <utility> #include <folly/Traits.h> #include <folly/Utility.h> #include <folly/functional/Invoke.h> #include <cstdint> namespace apache { namespace thrift { namespace detail { template <typename Tag> struct invoke_reffer; } // namespace detail template <typename Tag> using access_field_fn = detail::invoke_reffer<Tag>; template <typename Tag> FOLLY_INLINE_VARIABLE constexpr access_field_fn<Tag> access_field{}; enum FragileConstructor { FRAGILE, }; // re-definition of the same enums from // thrift/compiler/ast/t_exception.h enum class ExceptionKind { UNSPECIFIED = 0, TRANSIENT = 1, // The associated RPC may succeed if retried. STATEFUL = 2, // Server state must be change for the associated RPC to have // any chance of succeeding. PERMANENT = 3, // The associated RPC can never succeed, and should not be retried. }; enum class ExceptionBlame { UNSPECIFIED = 0, SERVER = 1, // The error was the fault of the server. CLIENT = 2, // The error was the fault of the client's request. }; enum class ExceptionSafety { UNSPECIFIED = 0, SAFE = 1, // It is guarneteed the associated RPC failed completely, and no // significant server state changed while trying to process the // RPC. }; namespace detail { namespace st { // struct_private_access // // Thrift structures have private members but it may be necessary for the // Thrift support library to access those private members. struct struct_private_access { // These should be alias templates but Clang has a bug where it does not // permit member alias templates of a friend struct to access private // members of the type to which it is a friend. Making these function // templates is a workaround. template <typename T> static folly::bool_constant<T::__fbthrift_cpp2_gen_json> // __fbthrift_cpp2_gen_json(); template <typename T> static folly::bool_constant<T::__fbthrift_cpp2_gen_nimble> // __fbthrift_cpp2_gen_nimble(); template <typename T> static folly::bool_constant<T::__fbthrift_cpp2_gen_has_thrift_uri> // __fbthrift_cpp2_gen_has_thrift_uri(); template <typename T> static typename T::__fbthrift_fields __fbthrift_fields(); template <typename T> using fields = decltype(__fbthrift_fields<T>()); template <typename T> static const char* __fbthrift_cpp2_gen_thrift_uri() { return T::__fbthrift_cpp2_gen_thrift_uri(); } template <typename T> static constexpr ExceptionSafety __fbthrift_cpp2_gen_exception_safety() { return T::__fbthrift_cpp2_gen_exception_safety; } template <typename T> static constexpr ExceptionKind __fbthrift_cpp2_gen_exception_kind() { return T::__fbthrift_cpp2_gen_exception_kind; } template <typename T> static constexpr ExceptionBlame __fbthrift_cpp2_gen_exception_blame() { return T::__fbthrift_cpp2_gen_exception_blame; } FOLLY_CREATE_MEMBER_INVOKER(clear_fn, __fbthrift_clear); FOLLY_CREATE_MEMBER_INVOKER(empty_fn, __fbthrift_is_empty); template <FieldId Id> struct get_fn { template <typename T> decltype(auto) operator()(T&& t) const { return static_cast<T&&>(t) .template __fbthrift_get<folly::to_underlying(Id)>(); } }; }; template <typename T, typename = void> struct IsThriftClass : std::false_type {}; template <typename T> struct IsThriftClass<T, folly::void_t<typename T::__fbthrift_cpp2_type>> : std::true_type {}; template <typename T, typename = void> struct IsThriftUnion : std::false_type {}; template <typename T> struct IsThriftUnion<T, folly::void_t<typename T::__fbthrift_cpp2_type>> : folly::bool_constant<T::__fbthrift_cpp2_is_union> {}; } // namespace st } // namespace detail using clear_fn = detail::st::struct_private_access::clear_fn; FOLLY_INLINE_VARIABLE constexpr clear_fn clear{}; using empty_fn = detail::st::struct_private_access::empty_fn; FOLLY_INLINE_VARIABLE static constexpr empty_fn empty{}; template <typename T> constexpr bool is_thrift_class_v = apache::thrift::detail::st::IsThriftClass<T>::value; template <typename T> constexpr bool is_thrift_union_v = apache::thrift::detail::st::IsThriftUnion<T>::value; template <typename T> constexpr bool is_thrift_exception_v = is_thrift_class_v<T>&& std::is_base_of<apache::thrift::TException, T>::value; template <typename T> constexpr bool is_thrift_struct_v = is_thrift_class_v<T> && !is_thrift_union_v<T> && !is_thrift_exception_v<T>; template <typename T, typename Fallback> using type_class_of_thrift_class_or_t = // folly::conditional_t< is_thrift_union_v<T>, type_class::variant, folly::conditional_t< is_thrift_class_v<T>, // struct or exception type_class::structure, Fallback>>; template <typename T, typename Fallback> using type_class_of_thrift_class_enum_or_t = // folly::conditional_t< std::is_enum<T>::value, type_class::enumeration, type_class_of_thrift_class_or_t<T, Fallback>>; template <typename T> using type_class_of_thrift_class_t = type_class_of_thrift_class_or_t<T, void>; template <typename T> using type_class_of_thrift_class_enum_t = type_class_of_thrift_class_enum_or_t<T, void>; namespace detail { template <typename T> struct enum_hash { size_t operator()(T t) const { using underlying_t = typename std::underlying_type<T>::type; return std::hash<underlying_t>()(underlying_t(t)); } }; } // namespace detail namespace detail { // Adapted from Fatal (https://github.com/facebook/fatal/) // Inlined here to keep the amount of mandatory dependencies at bay // For more context, see http://ericniebler.com/2013/08/07/ // - Universal References and the Copy Constructor template <typename, typename...> struct is_safe_overload { using type = std::true_type; }; template <typename Class, typename T> struct is_safe_overload<Class, T> { using type = std::integral_constant< bool, !std::is_same< Class, typename std::remove_cv< typename std::remove_reference<T>::type>::type>::value>; }; } // namespace detail template <typename Class, typename... Args> using safe_overload_t = typename std::enable_if< apache::thrift::detail::is_safe_overload<Class, Args...>::type::value>:: type; } // namespace thrift } // namespace apache #define FBTHRIFT_CPP_DEFINE_MEMBER_INDIRECTION_FN(...) \ struct __fbthrift_cpp2_indirection_fn { \ template <typename __fbthrift_t> \ FOLLY_ERASE constexpr auto operator()(__fbthrift_t&& __fbthrift_v) const \ noexcept( \ noexcept(static_cast<__fbthrift_t&&>(__fbthrift_v).__VA_ARGS__)) \ -> decltype(( \ static_cast<__fbthrift_t&&>(__fbthrift_v).__VA_ARGS__)) { \ return static_cast<__fbthrift_t&&>(__fbthrift_v).__VA_ARGS__; \ } \ } namespace apache { namespace thrift { template <typename T> using detect_indirection_fn_t = typename T::__fbthrift_cpp2_indirection_fn; template <typename T> using indirection_fn_t = folly::detected_or_t<folly::identity_fn, detect_indirection_fn_t, T>; namespace detail { struct apply_indirection_fn { private: template <typename T> using i = indirection_fn_t<folly::remove_cvref_t<T>>; public: template <typename T> FOLLY_ERASE constexpr auto operator()(T&& t) const noexcept(noexcept(i<T>{}(static_cast<T&&>(t)))) -> decltype(i<T>{}(static_cast<T&&>(t))) { return i<T>{}(static_cast<T&&>(t)); } }; } // namespace detail FOLLY_INLINE_VARIABLE constexpr detail::apply_indirection_fn apply_indirection; class ExceptionMetadataOverrideBase { public: virtual ~ExceptionMetadataOverrideBase() {} ExceptionKind errorKind() const { return errorKind_; } ExceptionBlame errorBlame() const { return errorBlame_; } ExceptionSafety errorSafety() const { return errorSafety_; } virtual const std::type_info* type() const = 0; protected: ExceptionKind errorKind_{ExceptionKind::UNSPECIFIED}; ExceptionBlame errorBlame_{ExceptionBlame::UNSPECIFIED}; ExceptionSafety errorSafety_{ExceptionSafety::UNSPECIFIED}; }; template <typename T> class ExceptionMetadataOverride : public T, public ExceptionMetadataOverrideBase { public: explicit ExceptionMetadataOverride(const T& t) : T(t) {} explicit ExceptionMetadataOverride(T&& t) : T(std::move(t)) {} const std::type_info* type() const override { #if FOLLY_HAS_RTTI return &typeid(T); #else return nullptr; #endif } // ExceptionKind ExceptionMetadataOverride& setTransient() { errorKind_ = ExceptionKind::TRANSIENT; return *this; } ExceptionMetadataOverride& setPermanent() { errorKind_ = ExceptionKind::PERMANENT; return *this; } ExceptionMetadataOverride& setStateful() { errorKind_ = ExceptionKind::STATEFUL; return *this; } // ExceptionBlame ExceptionMetadataOverride& setClient() { errorBlame_ = ExceptionBlame::CLIENT; return *this; } ExceptionMetadataOverride& setServer() { errorBlame_ = ExceptionBlame::SERVER; return *this; } // ExceptionSafety ExceptionMetadataOverride& setSafe() { errorSafety_ = ExceptionSafety::SAFE; return *this; } }; template <typename T> ExceptionMetadataOverride<std::decay_t<T>> overrideExceptionMetadata(T&& ex) { return ExceptionMetadataOverride<std::decay_t<T>>(std::forward<T>(ex)); } namespace detail { enum LazyDeserializationState : uint8_t { // Bitfield. UNTAINTED = 1 << 0, DESERIALIZED = 1 << 1, }; } // namespace detail } // namespace thrift } // namespace apache #endif // #ifndef THRIFT_CPP2_H_