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 <memory> 20 #include <type_traits> 21 22 #include <thrift/lib/cpp2/Thrift.h> 23 #include <thrift/lib/cpp2/protocol/Traits.h> 24 #include <thrift/lib/cpp2/protocol/detail/protocol_methods.h> 25 #include <thrift/lib/cpp2/reflection/reflection.h> 26 27 namespace apache { 28 namespace thrift { 29 namespace detail { 30 31 // is_smart_pointer is a helper for determining if a type is a supported 32 // pointer type for cpp2.ref fields, while discrimiminating against the 33 // pointer corner case in Thrift (e.g., a unqiue_pointer<folly::IOBuf>) 34 template <typename> 35 struct is_smart_pointer : std::false_type {}; 36 template <typename D> 37 struct is_smart_pointer<std::unique_ptr<folly::IOBuf, D>> : std::false_type {}; 38 39 // supported smart pointer types for cpp2.ref_type fields 40 template <typename T, typename D> 41 struct is_smart_pointer<std::unique_ptr<T, D>> : std::true_type {}; 42 template <typename T> 43 struct is_smart_pointer<std::shared_ptr<T>> : std::true_type {}; 44 45 template <typename T> 46 using enable_if_smart_pointer = 47 typename std::enable_if<is_smart_pointer<T>::value>::type; 48 49 template <typename T> 50 using disable_if_smart_pointer = 51 typename std::enable_if<!is_smart_pointer<T>::value>::type; 52 53 } /* namespace detail */ 54 55 namespace detail { 56 57 // helper predicate for determining if a struct's MemberInfo is required 58 // to be read out of the protocol 59 struct is_required_field { 60 template <typename MemberInfo> 61 using apply = std::integral_constant< 62 bool, 63 MemberInfo::optional::value == optionality::required>; 64 }; 65 66 struct extract_descriptor_fid { 67 template <typename T> 68 using apply = typename T::metadata::id; 69 }; 70 71 template <typename T, typename Enable = void> 72 struct deref; 73 74 // General case: methods on deref are no-op, returning their input 75 template <typename T> 76 struct deref<T, disable_if_smart_pointer<T>> { 77 static T& clear_and_get(T& in) { return in; } 78 static T const& get_const(T const& in) { return in; } 79 }; 80 81 // Special case: We specifically *do not* dereference a unique pointer to 82 // an IOBuf, because this is a type that the protocol can (de)serialize 83 // directly 84 template <> 85 struct deref<std::unique_ptr<folly::IOBuf>> { 86 using T = std::unique_ptr<folly::IOBuf>; 87 static T& clear_and_get(T& in) { return in; } 88 static T const& get_const(T const& in) { return in; } 89 }; 90 91 // General case: deref returns a reference to what the 92 // unique pointer contains 93 template <typename PtrType> 94 struct deref<PtrType, enable_if_smart_pointer<PtrType>> { 95 using T = typename std::remove_const<typename PtrType::element_type>::type; 96 static T& clear_and_get(std::shared_ptr<T const>& in) { 97 auto t = std::make_shared<T>(); 98 auto ret = t.get(); 99 in = std::move(t); 100 return *ret; 101 } 102 static T& clear_and_get(std::shared_ptr<T>& in) { 103 in = std::make_shared<T>(); 104 return *in; 105 } 106 static T& clear_and_get(std::unique_ptr<T>& in) { 107 in = std::make_unique<T>(); 108 return *in; 109 } 110 static T const& get_const(PtrType const& in) { return *in; } 111 }; 112 113 } // namespace detail 114 115 /** 116 * Entrypoints for using new serialization methods 117 * 118 * // C++ 119 * MyStruct a; 120 * MyUnion b; 121 * CompactProtocolReader reader; 122 * CompactProtocolReader writer; 123 * 124 * serializer_read(a, reader); 125 * serializer_write(b, writer); 126 * 127 * @author: Dylan Knutson <dymk@fb.com> 128 */ 129 130 template <typename Type, typename Protocol> 131 std::size_t serializer_read(Type& out, Protocol& protocol) { 132 using TypeClass = type_class_of_thrift_class_t<Type>; 133 auto xferStart = protocol.getCursorPosition(); 134 apache::thrift::detail::pm::protocol_methods<TypeClass, Type>::read( 135 protocol, out); 136 return protocol.getCursorPosition() - xferStart; 137 } 138 139 template <typename Type, typename Protocol> 140 std::size_t serializer_write(Type const& in, Protocol& protocol) { 141 using TypeClass = type_class_of_thrift_class_t<Type>; 142 return apache::thrift::detail::pm::protocol_methods<TypeClass, Type>::write( 143 protocol, in); 144 } 145 146 template <typename Type, typename Protocol> 147 std::size_t serializer_serialized_size(Type const& in, Protocol& protocol) { 148 using TypeClass = type_class_of_thrift_class_t<Type>; 149 return apache::thrift::detail::pm::protocol_methods<TypeClass, Type>:: 150 template serializedSize<false>(protocol, in); 151 } 152 153 template <typename Type, typename Protocol> 154 std::size_t serializer_serialized_size_zc(Type const& in, Protocol& protocol) { 155 using TypeClass = type_class_of_thrift_class_t<Type>; 156 return apache::thrift::detail::pm::protocol_methods<TypeClass, Type>:: 157 template serializedSize<true>(protocol, in); 158 } 159 160 } // namespace thrift 161 } // namespace apache 162