/* * 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. */ #pragma once #include #include #include #include #include namespace apache { namespace thrift { namespace python { namespace capi { namespace detail { namespace { template using to_thrift_wrap_method_t = decltype(std::declval().toThrift()); template constexpr bool is_wrap_v = folly::is_detected_v; } // namespace /** * Serialize C++ thrift struct `S` to IOBuf for python for structs and unions. * If `S` is a wrapped C++ struct, convert to thrift before serializing. */ template std::unique_ptr serialize_to_iobuf(const S& s) { if constexpr (apache::thrift::is_thrift_class_v) { folly::IOBufQueue queue; apache::thrift::BinaryProtocolWriter protocol; protocol.setOutput(&queue); s.write(&protocol); return queue.move(); } else if constexpr (is_wrap_v) { return serialize_to_iobuf(s.toThrift()); } else { static_assert( folly::always_false, "Serialize should take thrift class or wrapped thrift class"); } } /** * Deserialize C++ thrift struct `S` from IOBuf for structs and unions. * If `S` is a wrapped C++ struct, construct wrapper after deserializing. */ template S deserialize_iobuf(std::unique_ptr&& buf) { if constexpr (apache::thrift::is_thrift_class_v) { apache::thrift::BinaryProtocolReader protReader; protReader.setInput(buf.get()); S f; f.read(&protReader); return f; } else if constexpr (is_wrap_v) { return S{deserialize_iobuf( std::forward>(buf))}; } else { static_assert( folly::always_false, "Deserialize should take thrift class or wrapped thrift class type"); } } /** * Serialize an adapted thrift type T, which is return type of type adapter * A::fromThrift * * The `if` branch is an edge case for serializing a field adapter struct T. * This is needed to handle a field adapter denoted by a structured annotation * struct S annotated with cpp.Adapter and cpp.Transitive annotations. */ template std::unique_ptr serialize_adapted_to_iobuf(const T& s) { if constexpr (apache::thrift::is_thrift_class_v) { return serialize_to_iobuf(s); } else { return serialize_to_iobuf(Adapter::toThrift(s)); } } /** * Deserialize an adapted thrift type T, which is return type of type adapter * A::fromThrift * The `if` branch is an edge case for deserializing a field adapter struct T. * This is needed to handle a field adapter denoted by a structured annotation * struct T annotated with cpp.Adapter and cpp.Transitive annotations. */ template T deserialize_iobuf_to_adapted(std::unique_ptr&& buf) { if constexpr (apache::thrift::is_thrift_class_v) { return deserialize_iobuf(std::move(buf)); } else { using S = std::remove_reference_t()))>; return Adapter::fromThrift(deserialize_iobuf(std::move(buf))); } } /** * Sets a ValueError with the message from input TProtocolException. * Once thrift.python.ProtocolError is available, that will be raised instead. */ void handle_protocol_error(const apache::thrift::TProtocolException& e); } // namespace detail } // namespace capi } // namespace python } // namespace thrift } // namespace apache