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