thrift/lib/cpp2/protocol/NimbleProtocol-inl.h (496 lines of code) (raw):
/*
* 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 <thrift/lib/cpp2/protocol/NimbleProtocol.h>
#include <folly/Utility.h>
namespace apache {
namespace thrift {
using namespace detail::nimble;
inline uint32_t NimbleProtocolWriter::writeMessageBegin(
const std::string& /*name*/,
MessageType /*messageType*/,
int32_t /*seqid*/) {
return 0;
}
inline uint32_t NimbleProtocolWriter::writeMessageEnd() {
return 0;
}
inline uint32_t NimbleProtocolWriter::writeStructBegin(const char* /*name*/) {
return 0;
}
inline uint32_t NimbleProtocolWriter::writeStructEnd() {
encoder_.encodeFieldBytes(stopBytes());
return 0;
}
inline uint32_t NimbleProtocolWriter::writeFieldBegin(
const char* /*name*/, TType fieldType, int16_t fieldId) {
FieldBytes info = fieldBeginBytes(ttypeToNimbleType(fieldType), fieldId);
encoder_.encodeFieldBytes(info);
return 0;
}
inline uint32_t NimbleProtocolWriter::writeFieldEnd() {
return 0;
}
inline uint32_t NimbleProtocolWriter::writeFieldStop() {
return 0;
}
inline uint32_t NimbleProtocolWriter::writeMapBegin(
TType keyType, TType valType, uint32_t size) {
encoder_.encodeFieldBytes(
mapBeginByte(ttypeToNimbleType(keyType), ttypeToNimbleType(valType)));
encoder_.encodeSizeChunk(size);
return 0;
}
inline uint32_t NimbleProtocolWriter::writeMapEnd() {
return 0;
}
inline uint32_t NimbleProtocolWriter::writeCollectionBegin(
TType elemType, uint32_t size) {
encoder_.encodeFieldBytes(listBeginByte(ttypeToNimbleType(elemType)));
encoder_.encodeSizeChunk(size);
return 0;
}
inline uint32_t NimbleProtocolWriter::writeListBegin(
TType elemType, uint32_t size) {
return writeCollectionBegin(elemType, size);
}
inline uint32_t NimbleProtocolWriter::writeListEnd() {
return 0;
}
inline uint32_t NimbleProtocolWriter::writeSetBegin(
TType elemType, uint32_t size) {
return writeCollectionBegin(elemType, size);
}
inline uint32_t NimbleProtocolWriter::writeSetEnd() {
return 0;
}
inline uint32_t NimbleProtocolWriter::writeBool(bool value) {
encoder_.encodeContentChunk(value);
return 0;
}
inline uint32_t NimbleProtocolWriter::writeByte(int8_t byte) {
encoder_.encodeContentChunk(byte);
return 0;
}
inline uint32_t NimbleProtocolWriter::writeI16(int16_t i16) {
encoder_.encodeContentChunk(i16);
return 0;
}
inline uint32_t NimbleProtocolWriter::writeI32(int32_t i32) {
encoder_.encodeContentChunk(i32);
return 0;
}
inline uint32_t NimbleProtocolWriter::writeI64(int64_t i64) {
auto lower = static_cast<uint32_t>(i64 & 0xffffffff);
auto higher = static_cast<uint32_t>(i64 >> 32);
encoder_.encodeContentChunk(lower);
encoder_.encodeContentChunk(higher);
return 0;
}
inline uint32_t NimbleProtocolWriter::writeDouble(double dub) {
static_assert(sizeof(double) == sizeof(uint64_t), "");
static_assert(std::numeric_limits<double>::is_iec559, "");
return writeI64(folly::bit_cast<int64_t>(dub));
}
inline uint32_t NimbleProtocolWriter::writeFloat(float flt) {
static_assert(sizeof(float) == sizeof(uint32_t), "");
static_assert(std::numeric_limits<float>::is_iec559, "");
uint32_t bits = folly::bit_cast<uint32_t>(flt);
encoder_.encodeContentChunk(bits);
return 0;
}
inline uint32_t NimbleProtocolWriter::writeString(folly::StringPiece str) {
writeBinary(folly::ByteRange(str));
return 0;
}
inline uint32_t NimbleProtocolWriter::writeBinary(folly::StringPiece str) {
writeBinary(folly::ByteRange(str));
return 0;
}
inline uint32_t NimbleProtocolWriter::writeBinary(folly::ByteRange str) {
DCHECK_LE(str.size(), folly::to_unsigned(std::numeric_limits<int>::max()));
encoder_.encodeSizeChunk(folly::to_narrow(str.size()));
encoder_.encodeBinary(str.data(), str.size());
return 0;
}
inline uint32_t NimbleProtocolWriter::writeBinary(
const std::unique_ptr<folly::IOBuf>& str) {
if (!str) {
encoder_.encodeSizeChunk(0);
return 0;
}
return writeBinary(*str);
}
inline uint32_t NimbleProtocolWriter::writeBinary(const folly::IOBuf& str) {
size_t size = str.computeChainDataLength();
DCHECK_LE(size, folly::to_unsigned(std::numeric_limits<int>::max()));
encoder_.encodeSizeChunk(folly::to_narrow(size));
encoder_.encodeBinary(str.data(), size);
return 0;
}
/**
* Functions that return the serialized size
*/
inline uint32_t NimbleProtocolWriter::serializedMessageSize(
const std::string& /*name*/) const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedFieldSize(
const char* /*name*/, TType /*fieldType*/, int16_t /*fieldId*/) const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedStructSize(
const char* /*name*/) const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeMapBegin(
TType /*keyType*/, TType /*valType*/, uint32_t /*size*/) const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeMapEnd() const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeListBegin(
TType /*elemType*/, uint32_t /*size*/) const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeListEnd() const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeSetBegin(
TType /*elemType*/, uint32_t /*size*/) const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeSetEnd() const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeStop() const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeBool(bool /*val*/) const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeByte(int8_t /*val*/) const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeI16(int16_t /*val*/) const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeI32(int32_t /*val*/) const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeI64(int64_t /*val*/) const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeDouble(
double /*val*/) const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeFloat(float /*val*/) const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeString(
folly::StringPiece /*str*/) const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeBinary(
folly::StringPiece /*str*/) const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeBinary(
folly::ByteRange /*v*/) const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeBinary(
std::unique_ptr<folly::IOBuf> const& /*v*/) const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeBinary(
folly::IOBuf const& /*v*/) const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeZCBinary(
folly::StringPiece /*str*/) const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeZCBinary(
folly::ByteRange /*v*/) const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeZCBinary(
std::unique_ptr<folly::IOBuf> const& /*v*/) const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeZCBinary(
folly::IOBuf const& /*v*/) const {
return 0;
}
inline uint32_t NimbleProtocolWriter::serializedSizeSerializedData(
std::unique_ptr<folly::IOBuf> const& /*data*/) const {
return 0;
}
/**
* Reading functions
*/
inline void NimbleProtocolReader::readMessageBegin(
std::string& /*name*/, MessageType& /*messageType*/, int32_t& /*seqid*/) {}
inline void NimbleProtocolReader::readMessageEnd() {}
inline void NimbleProtocolReader::readStructBegin(const std::string& /*name*/) {
}
inline void NimbleProtocolReader::readStructEnd() {}
inline void NimbleProtocolReader::readFieldBegin(
std::string& /*name*/, NimbleType& /*fieldType*/, int16_t& /*fieldId*/) {}
inline void NimbleProtocolReader::readFieldEnd() {}
inline void NimbleProtocolReader::readMapBegin(
NimbleType& keyType, NimbleType& valType, uint32_t& size) {
std::uint8_t byte = decoder_.nextFieldByte();
mapTypesFromByte(byte, keyType, valType);
size = decoder_.nextSizeChunk();
if (size > static_cast<uint32_t>(container_limit_)) {
TProtocolException::throwExceededSizeLimit(size, container_limit_);
}
}
inline void NimbleProtocolReader::readMapEnd() {}
inline void NimbleProtocolReader::readListBegin(
NimbleType& elemType, uint32_t& size) {
std::uint8_t byte = decoder_.nextFieldByte();
listTypeFromByte(byte, elemType);
size = decoder_.nextSizeChunk();
if (size > static_cast<uint32_t>(container_limit_)) {
TProtocolException::throwExceededSizeLimit(size, container_limit_);
}
}
inline void NimbleProtocolReader::readListEnd() {}
inline void NimbleProtocolReader::readSetBegin(
NimbleType& elemType, uint32_t& size) {
readListBegin(elemType, size);
}
inline void NimbleProtocolReader::readSetEnd() {
readListEnd();
}
inline void NimbleProtocolReader::readBool(bool& value) {
value = static_cast<bool>(decoder_.nextContentChunk());
}
inline void NimbleProtocolReader::readBoolWithContext(
bool& value, StructReadState& srs) {
value = static_cast<bool>(decoder_.nextContentChunk(srs.decoderState));
}
inline void NimbleProtocolReader::readBool(std::vector<bool>::reference value) {
bool val;
readBool(val);
value = val;
}
inline void NimbleProtocolReader::readByte(int8_t& byte) {
byte = static_cast<int8_t>(decoder_.nextContentChunk());
}
inline void NimbleProtocolReader::readByteWithContext(
int8_t& byte, StructReadState& srs) {
byte = static_cast<int8_t>(decoder_.nextContentChunk(srs.decoderState));
}
inline void NimbleProtocolReader::readI16(int16_t& i16) {
i16 = static_cast<int16_t>(decoder_.nextContentChunk());
}
inline void NimbleProtocolReader::readI16WithContext(
int16_t& i16, StructReadState& srs) {
i16 = static_cast<int16_t>(decoder_.nextContentChunk(srs.decoderState));
}
inline void NimbleProtocolReader::readI32(int32_t& i32) {
i32 = static_cast<int32_t>(decoder_.nextContentChunk());
}
inline void NimbleProtocolReader::readI32WithContext(
int32_t& i32, StructReadState& srs) {
i32 = static_cast<int32_t>(decoder_.nextContentChunk(srs.decoderState));
}
inline void NimbleProtocolReader::readI64(int64_t& i64) {
auto lower = decoder_.nextContentChunk();
auto higher = decoder_.nextContentChunk();
i64 = static_cast<int64_t>(higher) << 32 | lower;
}
inline void NimbleProtocolReader::readI64WithContext(
int64_t& i64, StructReadState& srs) {
auto lower = decoder_.nextContentChunk(srs.decoderState);
auto higher = decoder_.nextContentChunk(srs.decoderState);
i64 = static_cast<int64_t>(higher) << 32 | lower;
}
inline void NimbleProtocolReader::readDouble(double& dub) {
static_assert(sizeof(double) == sizeof(uint64_t), "");
static_assert(std::numeric_limits<double>::is_iec559, "");
int64_t bits = 0;
readI64(bits);
dub = folly::bit_cast<double>(bits);
}
inline void NimbleProtocolReader::readDoubleWithContext(
double& dub, StructReadState& srs) {
static_assert(sizeof(double) == sizeof(uint64_t), "");
static_assert(std::numeric_limits<double>::is_iec559, "");
int64_t bits = 0;
readI64WithContext(bits, srs);
dub = folly::bit_cast<double>(bits);
}
inline void NimbleProtocolReader::readFloat(float& flt) {
static_assert(sizeof(float) == sizeof(uint32_t), "");
static_assert(std::numeric_limits<float>::is_iec559, "");
uint32_t bits = decoder_.nextContentChunk();
flt = folly::bit_cast<float>(bits);
}
inline void NimbleProtocolReader::readFloatWithContext(
float& flt, StructReadState& srs) {
static_assert(sizeof(float) == sizeof(uint32_t), "");
static_assert(std::numeric_limits<float>::is_iec559, "");
uint32_t bits = decoder_.nextContentChunk(srs.decoderState);
flt = folly::bit_cast<float>(bits);
}
template <typename StrType>
inline void NimbleProtocolReader::readString(StrType& str) {
uint32_t size = decoder_.nextSizeChunk();
if (size > static_cast<uint32_t>(string_limit_)) {
TProtocolException::throwExceededSizeLimit(size, string_limit_);
}
decoder_.nextBinary(str, size);
}
template <typename StrType>
inline void NimbleProtocolReader::readStringWithContext(
StrType& str, StructReadState& /* srs */) {
uint32_t size = decoder_.nextSizeChunk();
if (size > static_cast<uint32_t>(string_limit_)) {
TProtocolException::throwExceededSizeLimit(size, string_limit_);
}
decoder_.nextBinary(str, size);
}
template <typename StrType>
inline void NimbleProtocolReader::readBinary(StrType& str) {
readString(str);
}
template <typename StrType>
inline void NimbleProtocolReader::readBinaryWithContext(
StrType& str, StructReadState& /* srs */) {
readString(str);
}
inline void NimbleProtocolReader::readBinary(
std::unique_ptr<folly::IOBuf>& str) {
if (!str) {
str = std::make_unique<folly::IOBuf>();
}
readBinary(*str);
}
inline void NimbleProtocolReader::readBinaryWithContext(
std::unique_ptr<folly::IOBuf>& str, StructReadState& srs) {
if (!str) {
str = std::make_unique<folly::IOBuf>();
}
readBinaryWithContext(*str, srs);
}
inline void NimbleProtocolReader::readBinary(folly::IOBuf& str) {
uint32_t size = decoder_.nextSizeChunk();
if (size > static_cast<uint32_t>(string_limit_)) {
TProtocolException::throwExceededSizeLimit(size, string_limit_);
}
decoder_.nextBinary(str, size);
}
inline void NimbleProtocolReader::readBinaryWithContext(
folly::IOBuf& str, StructReadState& /* srs */) {
uint32_t size = decoder_.nextSizeChunk();
if (size > static_cast<uint32_t>(string_limit_)) {
TProtocolException::throwExceededSizeLimit(size, string_limit_);
}
decoder_.nextBinary(str, size);
}
inline void NimbleProtocolReader::skip_n(
std::uint32_t n, std::initializer_list<detail::nimble::NimbleType> types) {
StructReadState state;
state.borrowFieldPtrs(this);
state.decoderState = borrowState();
for (std::uint32_t i = 0; i < n; ++i) {
for (auto type : types) {
state.nimbleType = type;
state = skip(std::move(state));
}
}
state.returnFieldPtrs(this);
returnState(std::move(state.decoderState));
}
inline NimbleProtocolReader::StructReadState NimbleProtocolReader::skip(
StructReadState state) {
// As a precondition, state has borrowed from the protocol. So, in cases where
// we need to call a method that affects protocol state (like when skipping
// containers), we need to return and borrow it again before recursing into a
// skip call.
switch (state.nimbleType) {
case NimbleType::STOP: {
TProtocolException::throwInvalidSkipType(protocol::T_STOP);
}
case NimbleType::ONE_CHUNK: {
decoder_.nextContentChunk(state.decoderState);
break;
}
case NimbleType::TWO_CHUNK: {
decoder_.nextContentChunk(state.decoderState);
decoder_.nextContentChunk(state.decoderState);
break;
}
case NimbleType::STRING: {
std::uint32_t size = decoder_.nextSizeChunk();
decoder_.skipStringBytes(size);
break;
}
case NimbleType::STRUCT: {
while (true) {
state.readFieldBegin(this);
if (state.atStop()) {
break;
}
state = skip(std::move(state));
}
break;
}
case NimbleType::LIST: {
NimbleType elemType;
std::uint32_t size;
// Have to maintain borrowship precondition.
state.returnFieldPtrs(this);
readListBegin(elemType, size);
state.borrowFieldPtrs(this);
for (std::uint32_t i = 0; i < size; ++i) {
state.nimbleType = elemType;
state = skip(std::move(state));
}
break;
}
case NimbleType::MAP: {
NimbleType keyType;
NimbleType valueType;
std::uint32_t size;
// Have to maintain borrowship precondition.
state.returnFieldPtrs(this);
readMapBegin(keyType, valueType, size);
state.borrowFieldPtrs(this);
for (std::uint32_t i = 0; i < size; ++i) {
state.nimbleType = keyType;
state = skip(std::move(state));
state.nimbleType = valueType;
state = skip(std::move(state));
}
break;
}
case NimbleType::INVALID: {
TProtocolException::throwInvalidSkipType(protocol::T_STOP);
}
}
return state;
}
inline void NimbleProtocolReader::advanceToNextFieldSlow(
StructReadState& state) {
std::uint8_t firstByte = decoder_.nextFieldByte();
if (isCompactMetadata(firstByte)) {
// Short encoding
state.nimbleType = nimbleTypeFromCompactMetadata(firstByte);
state.fieldId = fieldIdFromCompactMetadata(firstByte);
} else {
state.nimbleType = nimbleTypeFromLargeMetadata(firstByte);
if (isLargeMetadataTwoByte(firstByte)) {
state.fieldId =
fieldIdFromTwoByteMetadata(firstByte, decoder_.nextFieldByte());
} else {
state.fieldId =
fieldIdFromThreeByteMetadata(firstByte, decoder_.nextFieldShort());
}
}
}
inline detail::BufferingNimbleDecoderState NimbleProtocolReader::borrowState() {
return decoder_.borrowState();
}
inline void NimbleProtocolReader::returnState(
detail::BufferingNimbleDecoderState state) {
decoder_.returnState(std::move(state));
}
bool NimbleProtocolReader::isCompatibleWithType(
TType expectedFieldType, StructReadState& state) {
return ttypeToNimbleType(expectedFieldType) == state.nimbleType;
}
} // namespace thrift
} // namespace apache