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 #pragma once
18 
19 #include <algorithm>
20 #include <cstdint>
21 #include <iterator>
22 #include <memory>
23 #include <type_traits>
24 #include <utility>
25 #include <vector>
26 
27 #include <folly/CPortability.h>
28 #include <folly/Optional.h>
29 #include <folly/Range.h>
30 #include <folly/Traits.h>
31 #include <folly/Utility.h>
32 #include <folly/container/View.h>
33 #include <thrift/lib/cpp/protocol/TType.h>
34 #include <thrift/lib/cpp2/FieldRefTraits.h>
35 #include <thrift/lib/cpp2/TypeClass.h>
36 #include <thrift/lib/cpp2/protocol/Protocol.h>
37 #include <thrift/lib/cpp2/protocol/TableBasedForwardTypes.h>
38 #include <thrift/lib/cpp2/protocol/detail/protocol_methods.h>
39 
40 namespace apache {
41 namespace thrift {
42 namespace detail {
43 
44 using FieldID = std::int16_t;
45 
46 // MSVC cannot reinterpret_cast an overloaded function to another function
47 // pointer, but piping the function through an identity function before
48 // reinterpret_cast works.
49 template <typename T>
identity(T t)50 FOLLY_ERASE constexpr T identity(T t) {
51   return t;
52 }
53 
54 template <typename T, typename U = void>
55 using enable_if_smart_ptr_t =
56     std::enable_if_t<is_shared_or_unique_ptr<T>::value, U>;
57 
58 template <typename T, typename U = void>
59 using enable_if_not_smart_ptr_t =
60     std::enable_if_t<!is_shared_or_unique_ptr<T>::value, U>;
61 
62 template <typename T, typename Enable = void>
63 struct maybe_get_element_type {
64   using type = T;
65 };
66 
67 template <typename T>
68 struct maybe_get_element_type<T, enable_if_smart_ptr_t<T>>
69     : maybe_get_element_type<std::remove_cv_t<typename T::element_type>> {};
70 
71 template <typename T>
72 using maybe_get_element_type_t = typename maybe_get_element_type<T>::type;
73 
74 enum class StringFieldType {
75   String,
76   StringView,
77   Binary,
78   IOBuf,
79   IOBufPtr,
80   IOBufObj,
81 };
82 
83 struct FieldInfo {
84   // Field id in thrift definition.
85   FieldID id;
86 
87   // Unqualified fields need to be differentiated from optional fields to always
88   // write unqualified fields despite the value of __isset.
89   bool isUnqualified;
90 
91   const char* name;
92 
93   // Offset into the data member of the field in the struct.
94   ptrdiff_t memberOffset;
95 
96   // 0 means that the field does not have __isset.
97   ptrdiff_t issetOffset;
98 
99   const TypeInfo* typeInfo;
100 };
101 
102 struct UnionExt {
103   // Clear union before setting a field.
104   VoidFuncPtr clear;
105 
106   ptrdiff_t unionTypeOffset;
107   int (*getActiveId)(const void*);
108   void (*setActiveId)(void*, int);
109 
110   // Value initializes using placement new into the member.
111   // Generated code should order this list by fields key order.
112   VoidFuncPtr initMember[];
113 };
114 
115 // Templatized version to const initialize with the exact array length.
116 template <std::int16_t NumFields>
117 struct UnionExtN {
118   VoidFuncPtr clear;
119   ptrdiff_t unionTypeOffset;
120   int (*getActiveId)(const void*);
121   void (*setActiveId)(void*, int);
122   VoidFuncPtr initMember[NumFields];
123 };
124 
125 struct StructInfo {
126   std::int16_t numFields;
127   const char* name;
128   // This should be set to nullptr when not a union.
129   const UnionExt* unionExt = nullptr;
130   bool (*getIsset)(const void*, ptrdiff_t);
131   void (*setIsset)(void*, ptrdiff_t, bool);
132   // Use for other languages to pass in additional information.
133   const void* customExt;
134   FieldInfo fieldInfos[];
135 };
136 
137 // Templatized version to const initialize with the exact array length.
138 template <std::int16_t NumFields>
139 struct StructInfoN {
140   std::int16_t numFields = NumFields;
141   const char* name;
142   const void* unionExt = nullptr;
143   bool (*getIsset)(const void*, ptrdiff_t);
144   void (*setIsset)(void*, ptrdiff_t, bool);
145   const void* customExt;
146   FieldInfo fieldInfos[NumFields];
147 };
148 
149 template <std::int16_t NumFields>
150 FOLLY_ERASE const StructInfo& toStructInfo(
151     const StructInfoN<NumFields>& templatizedInfo) {
152   return reinterpret_cast<const StructInfo&>(templatizedInfo);
153 }
154 
155 struct ListFieldExt {
156   const TypeInfo* valInfo;
157   std::uint32_t (*size)(const void* object);
158   void (*consumeElem)(
159       const void* context,
160       void* object,
161       void (*reader)(const void* context, void* val));
162   void (*readList)(
163       const void* context,
164       void* object,
165       std::uint32_t listSize,
166       void (*reader)(const void* context, void* val));
167   size_t (*writeList)(
168       const void* context,
169       const void* val,
170       size_t (*writer)(const void* context, const void* val));
171 };
172 
173 struct SetFieldExt {
174   const TypeInfo* valInfo;
175   std::uint32_t (*size)(const void* object);
176   void (*consumeElem)(
177       const void* context,
178       void* object,
179       void (*reader)(const void* context, void* val));
180   void (*readSet)(
181       const void* context,
182       void* object,
183       std::uint32_t setSize,
184       void (*reader)(const void* context, void* val));
185   size_t (*writeSet)(
186       const void* context,
187       const void* object,
188       bool protocolSortKeys,
189       size_t (*writer)(const void* context, const void* val));
190 };
191 
192 struct MapFieldExt {
193   const TypeInfo* keyInfo;
194   const TypeInfo* valInfo;
195   std::uint32_t (*size)(const void* object);
196   void (*consumeElem)(
197       const void* context,
198       void* object,
199       void (*keyReader)(const void* context, void* key),
200       void (*valueReader)(const void* context, void* val));
201   void (*readMap)(
202       const void* context,
203       void* object,
204       std::uint32_t mapSize,
205       void (*keyReader)(const void* context, void* key),
206       void (*valueReader)(const void* context, void* val));
207   size_t (*writeMap)(
208       const void* context,
209       const void* object,
210       bool protocolSortKeys,
211       size_t (*writer)(
212           const void* context, const void* keyElem, const void* valueElem));
213 };
214 
215 template <typename ThriftUnion>
216 void clearUnion(void* object) {
217   apache::thrift::clear(*reinterpret_cast<ThriftUnion*>(object));
218 }
219 
220 union ThriftValue {
221   explicit ThriftValue(bool value) : boolValue(value) {}
222   explicit ThriftValue(std::int8_t value) : int8Value(value) {}
223   explicit ThriftValue(std::int16_t value) : int16Value(value) {}
224   explicit ThriftValue(std::int32_t value) : int32Value(value) {}
225   explicit ThriftValue(std::int64_t value) : int64Value(value) {}
226   explicit ThriftValue(float value) : floatValue(value) {}
227   explicit ThriftValue(double value) : doubleValue(value) {}
228   explicit ThriftValue(const void* value) : object(value) {}
229   explicit ThriftValue(folly::IOBuf* value) : iobuf(value) {}
230   explicit ThriftValue(folly::StringPiece value) : stringViewValue(value) {}
231 
232   bool boolValue;
233   std::int8_t int8Value;
234   std::int16_t int16Value;
235   std::int32_t int32Value;
236   std::int64_t int64Value;
237   float floatValue;
238   double doubleValue;
239   const void* object;
240   folly::IOBuf* iobuf;
241   folly::StringPiece stringViewValue;
242 };
243 
244 using OptionalThriftValue = folly::Optional<ThriftValue>;
245 
246 template <typename PrimitiveType, typename ObjectType>
247 enable_if_not_smart_ptr_t<ObjectType, OptionalThriftValue> get(
248     const void* object) {
249   return folly::make_optional<ThriftValue>(
250       static_cast<PrimitiveType>(*static_cast<const ObjectType*>(object)));
251 }
252 
253 template <typename PrimitiveType, typename PtrType>
254 enable_if_smart_ptr_t<PtrType, OptionalThriftValue> get(const void* object) {
255   if (const auto* ptr = static_cast<const PtrType*>(object)->get()) {
256     return folly::make_optional<ThriftValue>(static_cast<PrimitiveType>(*ptr));
257   }
258   return folly::none;
259 }
260 
261 template <typename PtrType>
262 enable_if_smart_ptr_t<PtrType, OptionalThriftValue> get(const void* object) {
263   if (const void* ptr = static_cast<const PtrType*>(object)->get()) {
264     return folly::make_optional<ThriftValue>(ptr);
265   }
266   return folly::none;
267 }
268 
269 template <typename T, enable_if_not_smart_ptr_t<T, int> = 0>
270 constexpr auto getDerefFuncPtr() {
271   return nullptr;
272 }
273 
274 template <typename T, enable_if_smart_ptr_t<T, int> = 0>
275 constexpr auto getDerefFuncPtr() {
276   return get<T>;
277 }
278 
279 template <typename ObjectType>
280 enable_if_not_smart_ptr_t<ObjectType, void*> set(void* object) {
281   *static_cast<ObjectType*>(object) = ObjectType();
282   return object;
283 }
284 
285 template <typename PtrType>
286 std::enable_if_t<is_shared_ptr<PtrType>::value, void*> set(void* object) {
287   using Element = typename PtrType::element_type;
288   auto& ptr = *static_cast<PtrType*>(object);
289   ptr = std::make_shared<Element>();
290   return const_cast<std::remove_const_t<Element>*>(ptr.get());
291 }
292 
293 template <typename PtrType>
294 std::enable_if_t<is_unique_ptr<PtrType>::value, void*> set(void* object) {
295   using Element = typename PtrType::element_type;
296   auto& ptr = *static_cast<PtrType*>(object);
297   ptr = std::make_unique<Element>();
298   return const_cast<std::remove_const_t<Element>*>(ptr.get());
299 }
300 
301 template <typename ObjectType, typename PrimitiveType>
302 enable_if_not_smart_ptr_t<ObjectType> set(void* object, PrimitiveType val) {
303   *static_cast<ObjectType*>(object) = static_cast<ObjectType>(val);
304 }
305 
306 template <typename PtrType, typename PrimitiveType>
307 std::enable_if_t<is_unique_ptr<PtrType>::value> set(
308     void* object, PrimitiveType val) {
309   using Element = typename PtrType::element_type;
310   *static_cast<PtrType*>(object) =
311       std::make_unique<Element>(static_cast<Element>(val));
312 }
313 
314 template <typename PtrType, typename PrimitiveType>
315 std::enable_if_t<is_shared_ptr<PtrType>::value> set(
316     void* object, PrimitiveType val) {
317   using Element = typename PtrType::element_type;
318   *static_cast<PtrType*>(object) =
319       std::make_shared<Element>(static_cast<Element>(val));
320 }
321 
322 template <typename ValueType>
323 enable_if_not_smart_ptr_t<ValueType> placementNewUnionValue(void* object) {
324   ::new (object) ValueType();
325 }
326 
327 template <typename PtrType>
328 enable_if_smart_ptr_t<PtrType> placementNewUnionValue(void* object) {
329   ::new (object) PtrType(new typename PtrType::element_type());
330 }
331 
332 template <typename List>
333 size_t writeList(
334     const void* context,
335     const void* object,
336     size_t (*writer)(const void* /*context*/, const void* /*val*/)) {
337   const List& out = *static_cast<const List*>(object);
338   size_t written = 0;
339   for (auto& elem : out) {
340     written += writer(context, &elem);
341   }
342   return written;
343 }
344 
345 template <typename Set>
346 size_t writeSet(
347     const void* context,
348     const void* object,
349     bool protocolSortKeys,
350     size_t (*writer)(const void* /*context*/, const void* /*val*/)) {
351   const Set& out = *static_cast<const Set*>(object);
352   size_t written = 0;
353 
354   if (!folly::is_detected_v<
355           ::apache::thrift::detail::pm::detect_key_compare,
356           Set> &&
357       protocolSortKeys) {
358     std::vector<typename Set::const_iterator> iters;
359     iters.reserve(out.size());
360     for (auto it = out.begin(); it != out.end(); ++it) {
361       iters.push_back(it);
362     }
363     std::sort(
364         iters.begin(), iters.end(), [](auto a, auto b) { return *a < *b; });
365     for (auto it : iters) {
366       written += writer(context, &(*it));
367     }
368   } else {
369     // Support containers with defined but non-FIFO iteration order.
370     auto get_view = folly::order_preserving_reinsertion_view_or_default;
371     for (auto const& elem : get_view(out)) {
372       written += writer(context, &elem);
373     }
374   }
375   return written;
376 }
377 
378 template <typename Map>
379 size_t writeMap(
380     const void* context,
381     const void* object,
382     bool protocolSortKeys,
383     size_t (*writer)(
384         const void* /*context*/,
385         const void* /*keyElem*/,
386         const void* /*valueElem*/)) {
387   const Map& out = *static_cast<const Map*>(object);
388   size_t written = 0;
389   if (!folly::is_detected_v<
390           ::apache::thrift::detail::pm::detect_key_compare,
391           Map> &&
392       protocolSortKeys) {
393     std::vector<typename Map::const_iterator> iters;
394     iters.reserve(out.size());
395     for (auto it = out.begin(); it != out.end(); ++it) {
396       iters.push_back(it);
397     }
398     std::sort(iters.begin(), iters.end(), [](auto a, auto b) {
399       return a->first < b->first;
400     });
401     for (auto it : iters) {
402       written += writer(context, &it->first, &it->second);
403     }
404   } else {
405     // Support containers with defined but non-FIFO iteration order.
406     auto get_view = folly::order_preserving_reinsertion_view_or_default;
407     for (auto& elem_pair : get_view(out)) {
408       written += writer(context, &elem_pair.first, &elem_pair.second);
409     }
410   }
411   return written;
412 }
413 
414 template <typename Container>
415 std::uint32_t containerSize(const void* object) {
416   return folly::to_narrow(
417       folly::to_unsigned(static_cast<const Container*>(object)->size()));
418 }
419 
420 template <typename Map>
421 void consumeMapElem(
422     const void* context,
423     void* object,
424     void (*keyReader)(const void* /*context*/, void* /*key*/),
425     void (*valueReader)(const void* /*context*/, void* /*val*/)) {
426   Map& out = *static_cast<Map*>(object);
427   typename Map::key_type key;
428   keyReader(context, &key);
429   valueReader(context, &out[key]);
430 }
431 
432 template <typename Map>
433 void readMap(
434     const void* context,
435     void* object,
436     std::uint32_t mapSize,
437     void (*keyReader)(const void* /*context*/, void* /*key*/),
438     void (*valueReader)(const void* /*context*/, void* /*val*/)) {
439   Map& out = *static_cast<Map*>(object);
440   ::apache::thrift::detail::pm::reserve_if_possible(&out, mapSize);
441 
442   for (auto i = mapSize; i--;) {
443     typename Map::key_type key;
444     keyReader(context, &key);
445     valueReader(context, &out[key]);
446   }
447 }
448 
449 template <typename List>
450 void consumeListElem(
451     const void* context,
452     void* object,
453     void (*reader)(const void* /*context*/, void* /*val*/)) {
454   List& out = *static_cast<List*>(object);
455   out.emplace_back();
456   reader(context, &out.back());
457 }
458 
459 template <typename Set>
460 void consumeSetElem(
461     const void* context,
462     void* object,
463     void (*reader)(const void* /*context*/, void* /*val*/)) {
464   Set& out = *static_cast<Set*>(object);
465   typename Set::value_type tmp;
466   reader(context, &tmp);
467   out.insert(std::move(tmp));
468 }
469 
470 template <typename Set>
471 void readKnownLengthSet(
472     const void* context,
473     void* object,
474     std::uint32_t setSize,
475     void (*reader)(const void* /*context*/, void* /*val*/)) {
476   ::apache::thrift::detail::pm::reserve_if_possible(
477       static_cast<Set*>(object), setSize);
478 
479   while (setSize--) {
480     consumeSetElem<Set>(context, object, reader);
481   }
482 }
483 
484 template <typename List>
485 void readList(
486     const void* context,
487     void* object,
488     std::uint32_t listSize,
489     void (*reader)(const void* /*context*/, void* /*val*/)) {
490   List& out = *static_cast<List*>(object);
491   using traits = std::iterator_traits<typename List::iterator>;
492   using cat = typename traits::iterator_category;
493   if (::apache::thrift::detail::pm::reserve_if_possible(&out, listSize) ||
494       std::is_same<cat, std::bidirectional_iterator_tag>::value) {
495     while (listSize--) {
496       consumeListElem<List>(context, object, reader);
497     }
498   } else {
499     out.resize(listSize);
500     for (auto& elem : out) {
501       reader(context, &elem);
502     }
503   }
504 }
505 
506 #define THRIFT_DEFINE_PRIMITIVE_TYPE_TO_INFO(      \
507     TypeClass, Type, ThriftType, TTypeValue)       \
508   template <>                                      \
509   struct TypeToInfo<type_class::TypeClass, Type> { \
510     using underlying_type = ThriftType;            \
511     static const TypeInfo typeInfo;                \
512   }
513 
514 // Specializations for numbers.
515 THRIFT_DEFINE_PRIMITIVE_TYPE_TO_INFO(
516     integral, std::int8_t, std::int8_t, T_BYTE);
517 THRIFT_DEFINE_PRIMITIVE_TYPE_TO_INFO(
518     integral, std::int16_t, std::int16_t, T_I16);
519 THRIFT_DEFINE_PRIMITIVE_TYPE_TO_INFO(
520     integral, std::int32_t, std::int32_t, T_I32);
521 THRIFT_DEFINE_PRIMITIVE_TYPE_TO_INFO(
522     integral, std::int64_t, std::int64_t, T_I64);
523 THRIFT_DEFINE_PRIMITIVE_TYPE_TO_INFO(
524     integral, std::uint8_t, std::int8_t, T_BYTE);
525 THRIFT_DEFINE_PRIMITIVE_TYPE_TO_INFO(
526     integral, std::uint16_t, std::int16_t, T_I16);
527 THRIFT_DEFINE_PRIMITIVE_TYPE_TO_INFO(
528     integral, std::uint32_t, std::int32_t, T_I32);
529 THRIFT_DEFINE_PRIMITIVE_TYPE_TO_INFO(
530     integral, std::uint64_t, std::int64_t, T_I64);
531 THRIFT_DEFINE_PRIMITIVE_TYPE_TO_INFO(integral, bool, bool, T_BOOL);
532 THRIFT_DEFINE_PRIMITIVE_TYPE_TO_INFO(floating_point, float, float, T_FLOAT);
533 THRIFT_DEFINE_PRIMITIVE_TYPE_TO_INFO(floating_point, double, double, T_DOUBLE);
534 
535 #undef THRIFT_DEFINE_PRIMITIVE_TYPE_TO_INFO
536 
537 // Specialization for string.
538 #define THRIFT_DEFINE_STRING_TYPE_TO_INFO(TypeClass, T, ExtVal) \
539   template <>                                                   \
540   struct TypeToInfo<type_class::TypeClass, T> {                 \
541     static const StringFieldType ext;                           \
542     static const TypeInfo typeInfo;                             \
543   }
544 
545 THRIFT_DEFINE_STRING_TYPE_TO_INFO(string, std::string, StringFieldType::String);
546 THRIFT_DEFINE_STRING_TYPE_TO_INFO(
547     string, folly::fbstring, StringFieldType::String);
548 THRIFT_DEFINE_STRING_TYPE_TO_INFO(binary, std::string, StringFieldType::String);
549 THRIFT_DEFINE_STRING_TYPE_TO_INFO(
550     binary, folly::fbstring, StringFieldType::String);
551 THRIFT_DEFINE_STRING_TYPE_TO_INFO(binary, folly::IOBuf, StringFieldType::IOBuf);
552 THRIFT_DEFINE_STRING_TYPE_TO_INFO(
553     binary, std::unique_ptr<folly::IOBuf>, StringFieldType::IOBufPtr);
554 
555 #undef THRIFT_DEFINE_STRING_TYPE_TO_INFO
556 
557 // Specialization for set.
558 template <typename ElemTypeClass, typename T>
559 struct TypeToInfo<type_class::set<ElemTypeClass>, T> {
560   using set_type = maybe_get_element_type_t<T>;
561   static const SetFieldExt ext;
562   static const TypeInfo typeInfo;
563 };
564 
565 template <typename ElemTypeClass, typename T>
566 const SetFieldExt TypeToInfo<type_class::set<ElemTypeClass>, T>::ext = {
567     /* .valInfo */ &TypeToInfo<ElemTypeClass, typename set_type::value_type>::
568         typeInfo,
569     /* .size */ containerSize<set_type>,
570     /* .consumeElem */ consumeSetElem<set_type>,
571     /* .readSet */ readKnownLengthSet<set_type>,
572     /* .writeSet */ writeSet<set_type>,
573 };
574 
575 template <typename ElemTypeClass, typename T>
576 const TypeInfo TypeToInfo<type_class::set<ElemTypeClass>, T>::typeInfo = {
577     /* .type */ protocol::TType::T_SET,
578     /* .get */ getDerefFuncPtr<T>(),
579     /* .set */ reinterpret_cast<VoidFuncPtr>(set<T>),
580     /* .typeExt */
581     &TypeToInfo<type_class::set<ElemTypeClass>, T>::ext,
582 };
583 
584 // Specialization for list.
585 template <typename ElemTypeClass, typename T>
586 struct TypeToInfo<type_class::list<ElemTypeClass>, T> {
587   using list_type = maybe_get_element_type_t<T>;
588   static const ListFieldExt ext;
589   static const TypeInfo typeInfo;
590 };
591 template <typename ElemTypeClass, typename T>
592 const ListFieldExt TypeToInfo<type_class::list<ElemTypeClass>, T>::ext = {
593     /* .valInfo */ &TypeToInfo<ElemTypeClass, typename list_type::value_type>::
594         typeInfo,
595     /* .size */ containerSize<list_type>,
596     /* .consumeElem */ consumeListElem<list_type>,
597     /* .readList */ readList<list_type>,
598     /* .writeList */ writeList<list_type>,
599 };
600 template <typename ElemTypeClass, typename T>
601 const TypeInfo TypeToInfo<type_class::list<ElemTypeClass>, T>::typeInfo = {
602     /* .type */ protocol::TType::T_LIST,
603     /* .get */ getDerefFuncPtr<T>(),
604     /* .set */ reinterpret_cast<VoidFuncPtr>(set<T>),
605     /* .typeExt */ &ext,
606 };
607 
608 // Specialization for map.
609 template <typename KeyTypeClass, typename ValTypeClass, typename T>
610 struct TypeToInfo<type_class::map<KeyTypeClass, ValTypeClass>, T> {
611   using map_type = maybe_get_element_type_t<T>;
612   static const MapFieldExt ext;
613   static const TypeInfo typeInfo;
614 };
615 template <typename KeyTypeClass, typename ValTypeClass, typename T>
616 const MapFieldExt
617     TypeToInfo<type_class::map<KeyTypeClass, ValTypeClass>, T>::ext = {
618         /* .keyInfo */ &TypeToInfo<KeyTypeClass, typename map_type::key_type>::
619             typeInfo,
620         /* .valInfo */
621         &TypeToInfo<ValTypeClass, typename map_type::mapped_type>::typeInfo,
622         /* .size */ containerSize<map_type>,
623         /* .consumeElem */ consumeMapElem<map_type>,
624         /* .readMap */ readMap<map_type>,
625         /* .writeMap */ writeMap<map_type>,
626 };
627 template <typename KeyTypeClass, typename ValTypeClass, typename T>
628 const TypeInfo
629     TypeToInfo<type_class::map<KeyTypeClass, ValTypeClass>, T>::typeInfo = {
630         /* .type */ protocol::TType::T_MAP,
631         /* .get */ getDerefFuncPtr<T>(),
632         /* .set */ reinterpret_cast<VoidFuncPtr>(set<T>),
633         /* .typeExt */ &ext,
634 };
635 
636 // Specialization for smart pointers of type class struct and union.
637 #define THRIFT_DEFINE_STRUCT_PTR_TYPE_INFO(TypeClass)                     \
638   template <typename T>                                                   \
639   struct TypeToInfo<type_class::TypeClass, T, enable_if_smart_ptr_t<T>> { \
640     using struct_type = std::remove_cv_t<typename T::element_type>;       \
641     static const TypeInfo typeInfo;                                       \
642   };                                                                      \
643                                                                           \
644   template <typename T>                                                   \
645   const TypeInfo TypeToInfo<                                              \
646       type_class::TypeClass,                                              \
647       T,                                                                  \
648       enable_if_smart_ptr_t<T>>::typeInfo = {                             \
649       TypeToInfo<type_class::TypeClass, struct_type>::typeInfo.type,      \
650       get<T>,                                                             \
651       reinterpret_cast<VoidFuncPtr>(set<T>),                              \
652       TypeToInfo<type_class::TypeClass, struct_type>::typeInfo.typeExt,   \
653   }
654 
655 THRIFT_DEFINE_STRUCT_PTR_TYPE_INFO(structure);
656 THRIFT_DEFINE_STRUCT_PTR_TYPE_INFO(variant);
657 #undef THRIFT_DEFINE_STRUCT_PTR_TYPE_INFO
658 
659 // Specialization for smart pointers of numerical types.
660 #define THRIFT_DEFINE_NUMERIC_PTR_TYPE_INFO(TypeClass)                        \
661   template <typename T>                                                       \
662   struct TypeToInfo<type_class::TypeClass, T, enable_if_smart_ptr_t<T>> {     \
663     using numeric_type = std::remove_cv_t<typename T::element_type>;          \
664     using underlying_type =                                                   \
665         typename TypeToInfo<type_class::TypeClass, numeric_type>::            \
666             underlying_type;                                                  \
667     static const TypeInfo typeInfo;                                           \
668   };                                                                          \
669                                                                               \
670   template <typename T>                                                       \
671   const TypeInfo                                                              \
672       TypeToInfo<type_class::TypeClass, T, enable_if_smart_ptr_t<T>>::        \
673           typeInfo = {                                                        \
674               TypeToInfo<type_class::TypeClass, numeric_type>::typeInfo.type, \
675               get<underlying_type, T>,                                        \
676               reinterpret_cast<VoidFuncPtr>(set<T, underlying_type>),         \
677               nullptr,                                                        \
678   }
679 
680 THRIFT_DEFINE_NUMERIC_PTR_TYPE_INFO(integral);
681 THRIFT_DEFINE_NUMERIC_PTR_TYPE_INFO(floating_point);
682 #undef THRIFT_DEFINE_NUMERIC_PTR_TYPE_INFO
683 
684 template <class ThriftStruct>
685 constexpr ptrdiff_t fieldOffset(std::int16_t fieldIndex);
686 
687 template <class ThriftStruct>
688 constexpr ptrdiff_t issetOffset(std::int16_t fieldIndex);
689 
690 template <class ThriftUnion>
691 constexpr ptrdiff_t unionTypeOffset();
692 
693 template <class Protocol_>
694 void read(Protocol_* iprot, const StructInfo& structInfo, void* object);
695 
696 template <class Protocol_>
697 size_t write(
698     Protocol_* iprot, const StructInfo& structInfo, const void* object);
699 
700 } // namespace detail
701 } // namespace thrift
702 } // namespace apache
703