1 /* 2 * Copyright (c) Facebook, Inc. and its affiliates. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef THRIFT_CPP2_H_ 18 #define THRIFT_CPP2_H_ 19 20 #include <thrift/lib/cpp/Thrift.h> 21 #include <thrift/lib/cpp2/TypeClass.h> 22 23 #include <initializer_list> 24 #include <utility> 25 #include <folly/Traits.h> 26 #include <folly/Utility.h> 27 #include <folly/functional/Invoke.h> 28 29 #include <cstdint> 30 31 namespace apache { 32 namespace thrift { 33 34 enum FragileConstructor { 35 FRAGILE, 36 }; 37 38 // re-definition of the same enums from 39 // thrift/compiler/ast/t_exception.h 40 enum class ExceptionKind { 41 UNSPECIFIED = 0, 42 TRANSIENT = 1, // The associated RPC may succeed if retried. 43 STATEFUL = 2, // Server state must be change for the associated RPC to have 44 // any chance of succeeding. 45 PERMANENT = 46 3, // The associated RPC can never succeed, and should not be retried. 47 }; 48 49 enum class ExceptionBlame { 50 UNSPECIFIED = 0, 51 SERVER = 1, // The error was the fault of the server. 52 CLIENT = 2, // The error was the fault of the client's request. 53 }; 54 55 enum class ExceptionSafety { 56 UNSPECIFIED = 0, 57 SAFE = 1, // It is guarneteed the associated RPC failed completely, and no 58 // significant server state changed while trying to process the 59 // RPC. 60 }; 61 62 namespace detail { 63 namespace st { 64 65 // struct_private_access 66 // 67 // Thrift structures have private members but it may be necessary for the 68 // Thrift support library to access those private members. 69 struct struct_private_access { 70 // These should be alias templates but Clang has a bug where it does not 71 // permit member alias templates of a friend struct to access private 72 // members of the type to which it is a friend. Making these function 73 // templates is a workaround. 74 template <typename T> 75 static folly::bool_constant<T::__fbthrift_cpp2_gen_json> // 76 __fbthrift_cpp2_gen_json(); 77 78 template <typename T> 79 static folly::bool_constant<T::__fbthrift_cpp2_gen_nimble> // 80 __fbthrift_cpp2_gen_nimble(); 81 82 template <typename T> 83 static folly::bool_constant<T::__fbthrift_cpp2_gen_has_thrift_uri> // 84 __fbthrift_cpp2_gen_has_thrift_uri(); 85 86 template <typename T> __fbthrift_cpp2_gen_thrift_uristruct_private_access87 static const char* __fbthrift_cpp2_gen_thrift_uri() { 88 return T::__fbthrift_cpp2_gen_thrift_uri(); 89 } 90 91 template <typename T> __fbthrift_cpp2_gen_exception_safetystruct_private_access92 static constexpr ExceptionSafety __fbthrift_cpp2_gen_exception_safety() { 93 return T::__fbthrift_cpp2_gen_exception_safety; 94 } 95 96 template <typename T> __fbthrift_cpp2_gen_exception_kindstruct_private_access97 static constexpr ExceptionKind __fbthrift_cpp2_gen_exception_kind() { 98 return T::__fbthrift_cpp2_gen_exception_kind; 99 } 100 101 template <typename T> __fbthrift_cpp2_gen_exception_blamestruct_private_access102 static constexpr ExceptionBlame __fbthrift_cpp2_gen_exception_blame() { 103 return T::__fbthrift_cpp2_gen_exception_blame; 104 } 105 106 FOLLY_CREATE_MEMBER_INVOKER(clear_fn, __fbthrift_clear); 107 }; 108 109 template <typename T, typename = void> 110 struct IsThriftClass : std::false_type {}; 111 112 template <typename T> 113 struct IsThriftClass<T, folly::void_t<typename T::__fbthrift_cpp2_type>> 114 : std::true_type {}; 115 116 template <typename T, typename = void> 117 struct IsThriftUnion : std::false_type {}; 118 119 template <typename T> 120 struct IsThriftUnion<T, folly::void_t<typename T::__fbthrift_cpp2_type>> 121 : folly::bool_constant<T::__fbthrift_cpp2_is_union> {}; 122 123 } // namespace st 124 } // namespace detail 125 126 using clear_fn = detail::st::struct_private_access::clear_fn; 127 FOLLY_INLINE_VARIABLE constexpr clear_fn clear{}; 128 129 template <typename T> 130 constexpr bool is_thrift_class_v = 131 apache::thrift::detail::st::IsThriftClass<T>::value; 132 133 template <typename T> 134 constexpr bool is_thrift_union_v = 135 apache::thrift::detail::st::IsThriftUnion<T>::value; 136 137 template <typename T> 138 constexpr bool is_thrift_exception_v = is_thrift_class_v<T>&& 139 std::is_base_of<apache::thrift::TException, T>::value; 140 141 template <typename T> 142 constexpr bool is_thrift_struct_v = 143 is_thrift_class_v<T> && !is_thrift_union_v<T> && !is_thrift_exception_v<T>; 144 145 template <typename T, typename Fallback> 146 using type_class_of_thrift_class_or_t = // 147 folly::conditional_t< 148 is_thrift_union_v<T>, 149 type_class::variant, 150 folly::conditional_t< 151 is_thrift_class_v<T>, // struct or exception 152 type_class::structure, 153 Fallback>>; 154 155 template <typename T, typename Fallback> 156 using type_class_of_thrift_class_enum_or_t = // 157 folly::conditional_t< 158 std::is_enum<T>::value, 159 type_class::enumeration, 160 type_class_of_thrift_class_or_t<T, Fallback>>; 161 162 template <typename T> 163 using type_class_of_thrift_class_t = type_class_of_thrift_class_or_t<T, void>; 164 165 template <typename T> 166 using type_class_of_thrift_class_enum_t = 167 type_class_of_thrift_class_enum_or_t<T, void>; 168 169 namespace detail { 170 171 template <typename T> 172 struct enum_hash { 173 size_t operator()(T t) const { 174 using underlying_t = typename std::underlying_type<T>::type; 175 return std::hash<underlying_t>()(underlying_t(t)); 176 } 177 }; 178 179 } // namespace detail 180 181 namespace detail { 182 183 // Adapted from Fatal (https://github.com/facebook/fatal/) 184 // Inlined here to keep the amount of mandatory dependencies at bay 185 // For more context, see http://ericniebler.com/2013/08/07/ 186 // - Universal References and the Copy Constructor 187 template <typename, typename...> 188 struct is_safe_overload { 189 using type = std::true_type; 190 }; 191 template <typename Class, typename T> 192 struct is_safe_overload<Class, T> { 193 using type = std::integral_constant< 194 bool, 195 !std::is_same< 196 Class, 197 typename std::remove_cv< 198 typename std::remove_reference<T>::type>::type>::value>; 199 }; 200 201 } // namespace detail 202 203 template <typename Class, typename... Args> 204 using safe_overload_t = typename std::enable_if< 205 apache::thrift::detail::is_safe_overload<Class, Args...>::type::value>:: 206 type; 207 208 } // namespace thrift 209 } // namespace apache 210 211 #define FBTHRIFT_CPP_DEFINE_MEMBER_INDIRECTION_FN(...) \ 212 struct __fbthrift_cpp2_indirection_fn { \ 213 template <typename __fbthrift_t> \ 214 FOLLY_ERASE constexpr auto operator()(__fbthrift_t&& __fbthrift_v) const \ 215 noexcept( \ 216 noexcept(static_cast<__fbthrift_t&&>(__fbthrift_v).__VA_ARGS__)) \ 217 -> decltype(( \ 218 static_cast<__fbthrift_t&&>(__fbthrift_v).__VA_ARGS__)) { \ 219 return static_cast<__fbthrift_t&&>(__fbthrift_v).__VA_ARGS__; \ 220 } \ 221 } 222 223 namespace apache { 224 namespace thrift { 225 226 template <typename T> 227 using detect_indirection_fn_t = typename T::__fbthrift_cpp2_indirection_fn; 228 229 template <typename T> 230 using indirection_fn_t = 231 folly::detected_or_t<folly::identity_fn, detect_indirection_fn_t, T>; 232 233 namespace detail { 234 struct apply_indirection_fn { 235 private: 236 template <typename T> 237 using i = indirection_fn_t<folly::remove_cvref_t<T>>; 238 239 public: 240 template <typename T> 241 FOLLY_ERASE constexpr auto operator()(T&& t) const 242 noexcept(noexcept(i<T>{}(static_cast<T&&>(t)))) 243 -> decltype(i<T>{}(static_cast<T&&>(t))) { 244 return i<T>{}(static_cast<T&&>(t)); 245 } 246 }; 247 } // namespace detail 248 249 FOLLY_INLINE_VARIABLE constexpr detail::apply_indirection_fn apply_indirection; 250 251 class ExceptionMetadataOverrideBase { 252 public: 253 virtual ~ExceptionMetadataOverrideBase() {} 254 255 ExceptionKind errorKind() const { return errorKind_; } 256 257 ExceptionBlame errorBlame() const { return errorBlame_; } 258 259 ExceptionSafety errorSafety() const { return errorSafety_; } 260 261 virtual const std::type_info* type() const = 0; 262 263 protected: 264 ExceptionKind errorKind_{ExceptionKind::UNSPECIFIED}; 265 ExceptionBlame errorBlame_{ExceptionBlame::UNSPECIFIED}; 266 ExceptionSafety errorSafety_{ExceptionSafety::UNSPECIFIED}; 267 }; 268 269 template <typename T> 270 class ExceptionMetadataOverride : public T, 271 public ExceptionMetadataOverrideBase { 272 public: 273 explicit ExceptionMetadataOverride(const T& t) : T(t) {} 274 explicit ExceptionMetadataOverride(T&& t) : T(std::move(t)) {} 275 276 const std::type_info* type() const override { 277 #if FOLLY_HAS_RTTI 278 return &typeid(T); 279 #else 280 return nullptr; 281 #endif 282 } 283 284 // ExceptionKind 285 ExceptionMetadataOverride& setTransient() { 286 errorKind_ = ExceptionKind::TRANSIENT; 287 return *this; 288 } 289 ExceptionMetadataOverride& setPermanent() { 290 errorKind_ = ExceptionKind::PERMANENT; 291 return *this; 292 } 293 ExceptionMetadataOverride& setStateful() { 294 errorKind_ = ExceptionKind::STATEFUL; 295 return *this; 296 } 297 298 // ExceptionBlame 299 ExceptionMetadataOverride& setClient() { 300 errorBlame_ = ExceptionBlame::CLIENT; 301 return *this; 302 } 303 ExceptionMetadataOverride& setServer() { 304 errorBlame_ = ExceptionBlame::SERVER; 305 return *this; 306 } 307 308 // ExceptionSafety 309 ExceptionMetadataOverride& setSafe() { 310 errorSafety_ = ExceptionSafety::SAFE; 311 return *this; 312 } 313 }; 314 315 template <typename T> 316 ExceptionMetadataOverride<std::decay_t<T>> overrideExceptionMetadata(T&& ex) { 317 return ExceptionMetadataOverride<std::decay_t<T>>(std::forward<T>(ex)); 318 } 319 320 namespace detail { 321 322 enum LazyDeserializationState : uint8_t { // Bitfield. 323 UNTAINTED = 1 << 0, 324 DESERIALIZED = 1 << 1, 325 }; 326 327 } // namespace detail 328 329 } // namespace thrift 330 } // namespace apache 331 332 #endif // #ifndef THRIFT_CPP2_H_ 333