/* * 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 #include #include #include #include #include #include namespace apache::thrift::protocol { // Creates a Value struct for the given value. // // TT: The thrift type to use, for example // apache::thrift::type::binary_t. using detail::asValueStruct; // Creates a Object struct for the given structured. template std::enable_if_t< is_thrift_struct_v> || is_thrift_union_v>, Object> asObject(T&& obj) { return asValueStruct(std::forward(obj)).as_object(); } // Schemaless deserialization of thrift serialized data // into protocol::Object // Protocol: protocol to use eg. apache::thrift::BinaryProtocolReader // buf: serialized payload // Works for binary, compact. Does not work for SimpleJson protocol as it does // not save fieldID and field type information in serialized data. Does not work // with json protocol because both binary & string is marked as T_STRING type in // serailized data but both are encoded differently. Binary is base64 encoded // and string is written as is. So during deserialization we cannot decode it // correctly without schema. String fields are currently saved in binaryValue. template Object parseObject(const folly::IOBuf& buf, bool string_to_binary = true) { Protocol prot; prot.setInput(&buf); auto result = detail::parseValue(prot, protocol::T_STRUCT, string_to_binary); return std::move(*result.objectValue_ref()); } // Schemaless deserialization of thrift serialized data with mask. // Only parses values that are masked. Unmasked fields are stored in MaskedData. template Object parseObjectWithoutExcludedData( const folly::IOBuf& buf, const Mask& mask, bool string_to_binary = true) { return detail::parseObject( buf, mask, noneMask(), string_to_binary) .included; } // Schemaless deserialization of thrift serialized data with mask. // Only parses values that are masked. Unmasked fields are stored in MaskedData. template MaskedDecodeResult parseObject( const folly::IOBuf& buf, const Mask& mask, bool string_to_binary = true) { return detail::parseObject( buf, mask, noneMask(), string_to_binary); } // Schemaless deserialization of thrift serialized data with readMask and // writeMask. Only parses values that are masked by readMask. Fields that are // not in neither writeMask nor readMask are stored in MaskedData. template MaskedDecodeResult parseObject( const folly::IOBuf& buf, const Mask& readMask, const Mask& writeMask, bool string_to_binary = true) { return detail::parseObject< Protocol, true /* always keep excluded data with writeMask */>( buf, readMask, writeMask, string_to_binary); } // Schemaless serialization of protocol::Value into thrift serialization // protocol Protocol: protocol to use eg. apache::thrift::BinaryProtocolWriter // val: Value to be serialized Serialized output is same as schema based // serialization except when struct contains an empty list, set or map using detail::serializeValue; // Schemaless serialization of protocol::Object into thrift serialization // protocol Protocol: protocol to use eg. apache::thrift::BinaryProtocolWriter // obj: object to be serialized Serialized output is same as schema based // serialization except when struct contains an empty list, set or map template void serializeObject(const Object& val, folly::IOBufQueue& queue) { Protocol prot; prot.setOutput(&queue); detail::serializeObject(prot, val); } template std::unique_ptr serializeObject(const Object& val) { folly::IOBufQueue queue(folly::IOBufQueue::cacheChainLength()); serializeObject(val, queue); return queue.move(); } // Serialization of protocol::Object with MaskedProtocolData. template std::unique_ptr serializeObject( const Object& obj, const MaskedProtocolData& protocolData) { assert(*protocolData.protocol() == detail::get_standard_protocol); Protocol prot; folly::IOBufQueue queue(folly::IOBufQueue::cacheChainLength()); prot.setOutput(&queue); if (protocolData.data()->full_ref()) { // entire object is not parsed const EncodedValue& value = detail::getByValueId( *protocolData.values(), protocolData.data()->full_ref().value()); prot.writeRaw(*value.data()); } else if (!protocolData.data()->fields_ref()) { // entire object is parsed detail::serializeObject(prot, obj); } else { // use both object and masked data to serialize detail::serializeObject(prot, obj, protocolData, *protocolData.data()); } return queue.move(); } template Value parseValue( const folly::IOBuf& buf, apache::thrift::type::BaseType baseType, bool string_to_binary = true) { Protocol prot; prot.setInput(&buf); return detail::parseValue(prot, type::toTType(baseType), string_to_binary); } template Value parseValue(const folly::IOBuf& buf, bool string_to_binary = true) { return parseValue( buf, type::detail::getBaseType(Tag{}), string_to_binary); } /// Convert protocol::Value to native thrift value. template auto fromValueStruct(const protocol::Value& v) { type::native_type t; detail::ProtocolValueToThriftValue{}(v, t); return t; } /// Convert protocol::Object to native thrift value. template auto fromObjectStruct(const protocol::Object& o) { type::native_type t; detail::ProtocolValueToThriftValue{}(o, t); return t; } // Returns whether the protocol::Value/ Object is its intrinsic default. bool isIntrinsicDefault(const Value& value); bool isIntrinsicDefault(const Object& obj); folly::dynamic toDynamic(const Value& value); folly::dynamic toDynamic(const Object& obj); using detail::toAny; } // namespace apache::thrift::protocol