in thrift/lib/cpp2/util/DebugString.cpp [431:715]
void parseField(
TType expectedType,
folly::StringPiece extendedExpectedType,
Tokenizer& tokenizer,
ProtocolWriter* outProtoWriter) {
auto getNextOrThrow = [&]() -> folly::StringPiece {
auto sp = tokenizer.getNextToken();
if (sp.empty()) {
throw TProtocolException(
TProtocolException::INVALID_DATA, "Unexpected end of data");
}
return sp;
};
switch (expectedType) {
case TType::T_BOOL: {
auto tok = getNextOrThrow();
if (tok == "true") {
if (outProtoWriter) {
outProtoWriter->writeBool(true);
}
} else if (tok == "false") {
if (outProtoWriter) {
outProtoWriter->writeBool(false);
}
} else {
throw TProtocolException(
TProtocolException::INVALID_DATA,
fmt::format("Bad bool token {}", tok));
}
break;
}
case TType::T_BYTE: {
int8_t val = folly::to<int8_t>(getNextOrThrow());
if (outProtoWriter) {
outProtoWriter->writeByte(val);
}
break;
}
case TType::T_I16: {
int16_t val = folly::to<int16_t>(getNextOrThrow());
if (outProtoWriter) {
outProtoWriter->writeI16(val);
}
break;
}
case TType::T_I32: {
int32_t val = folly::to<int32_t>(getNextOrThrow());
if (outProtoWriter) {
outProtoWriter->writeI32(val);
}
break;
}
case TType::T_I64: {
int64_t val = folly::to<int64_t>(getNextOrThrow());
if (outProtoWriter) {
outProtoWriter->writeI64(val);
}
break;
}
case TType::T_DOUBLE: {
double val = folly::to<double>(getNextOrThrow());
if (outProtoWriter) {
outProtoWriter->writeDouble(val);
}
break;
}
case TType::T_FLOAT: {
float val = folly::to<float>(getNextOrThrow());
if (outProtoWriter) {
outProtoWriter->writeFloat(val);
}
break;
}
case TType::T_STRING: {
auto tok = getNextOrThrow();
if (tok.size() < 2 || tok.front() != '"' || tok.back() != '"') {
throw TProtocolException(
TProtocolException::INVALID_DATA,
fmt::format("Bad string token {}", tok));
}
tok.pop_back();
tok.pop_front();
std::string unescaped;
folly::cUnescape(tok, unescaped);
if (outProtoWriter) {
outProtoWriter->writeString(unescaped);
}
break;
}
case TType::T_STRUCT: {
auto tok = getNextOrThrow();
if (tok == "struct") {
tok = getNextOrThrow();
}
if (tok != "{") {
throw TProtocolException(
TProtocolException::INVALID_DATA,
fmt::format("Expected struct '{{' at {}", tok));
}
if (outProtoWriter) {
outProtoWriter->writeStructBegin("");
}
for (;;) {
tok = getNextOrThrow();
if (tok == "}") {
if (outProtoWriter) {
outProtoWriter->writeFieldStop();
outProtoWriter->writeStructEnd();
}
break;
}
if (tok.back() != ':') {
throw TProtocolException(
TProtocolException::INVALID_DATA,
fmt::format("Expected tag: {}", tok));
}
tok.pop_back();
int16_t tagnum = folly::to<int16_t>(tok);
folly::StringPiece fullType = getNextOrThrow();
TType typeId = parseSimpleTypeLabel(fullType);
if (typeId == TType::T_STOP) {
throw TProtocolException(
TProtocolException::INVALID_DATA,
fmt::format("Unexpected type {}", fullType));
}
if (getNextOrThrow() != "=") {
throw TProtocolException(
TProtocolException::INVALID_DATA, "Missing = delim in struct");
}
if (outProtoWriter) {
outProtoWriter->writeFieldBegin("", typeId, tagnum);
}
parseField(typeId, fullType, tokenizer, outProtoWriter);
if (outProtoWriter) {
outProtoWriter->writeFieldEnd();
}
}
break;
}
case TType::T_LIST:
case TType::T_SET: {
folly::StringPiece elemTypeStr = getInnerTypeLabel(extendedExpectedType);
TType elemTypeId = parseSimpleTypeLabel(elemTypeStr);
if (elemTypeId == TType::T_STOP) {
throw TProtocolException(
TProtocolException::INVALID_DATA,
fmt::format("Cannot parse element type in {}", elemTypeStr));
}
folly::StringPiece openDelim, closeDelim;
if (expectedType == TType::T_LIST) {
openDelim = "[";
closeDelim = "]";
} else {
openDelim = "{";
closeDelim = "}";
}
if (getNextOrThrow() != openDelim) {
throw TProtocolException(
TProtocolException::INVALID_DATA, "Missing open delimiter");
}
// Count the number of elements. Unfortunately, the involves parsing the
// data. We parse to a null writer, and copy the tokenizer.
size_t numElems = 0;
auto tokenizerCopy = tokenizer; // cheap
for (;;) {
auto peekTokenizer = tokenizerCopy;
auto delim = peekTokenizer.getNextToken();
if (delim.empty()) {
throw TProtocolException(
TProtocolException::INVALID_DATA, "Premature end of stream");
}
if (delim == closeDelim) {
break;
}
parseField(
elemTypeId,
elemTypeStr,
tokenizerCopy,
static_cast<ProtocolWriter*>(nullptr));
numElems++;
}
if (outProtoWriter) {
if (expectedType == TType::T_LIST) {
outProtoWriter->writeListBegin(elemTypeId, numElems);
} else {
outProtoWriter->writeSetBegin(elemTypeId, numElems);
}
}
// Parse the actual elements
for (size_t i = 0; i < numElems; ++i) {
parseField(elemTypeId, elemTypeStr, tokenizer, outProtoWriter);
}
if (getNextOrThrow() != closeDelim) {
throw TProtocolException(
TProtocolException::INVALID_DATA, "Missing closing delimiter");
}
if (outProtoWriter) {
if (expectedType == TType::T_LIST) {
outProtoWriter->writeListEnd();
} else {
outProtoWriter->writeSetEnd();
}
}
break;
}
case TType::T_MAP: {
std::pair<folly::StringPiece, folly::StringPiece> keyValSplit =
splitMapKeyValueType(getInnerTypeLabel(extendedExpectedType));
TType keyTypeId = parseSimpleTypeLabel(keyValSplit.first);
TType valTypeId = parseSimpleTypeLabel(keyValSplit.second);
if (keyTypeId == TType::T_STOP || valTypeId == TType::T_STOP) {
throw TProtocolException(
TProtocolException::INVALID_DATA,
fmt::format("Cannot parse map types: {}", extendedExpectedType));
}
if (getNextOrThrow() != "{") {
throw TProtocolException(
TProtocolException::INVALID_DATA, "Missing { delimiter in map");
}
// Need to count the elements, which requires a pre-pass.
// Parse with a tokenizerCopy and discard the results.
auto tokenizerCopy = tokenizer; // cheap
size_t numElems = 0;
for (;;) {
auto peekTokenizer = tokenizerCopy;
auto delim = peekTokenizer.getNextToken();
if (delim.empty()) {
throw TProtocolException(
TProtocolException::INVALID_DATA, "Premature end of stream");
}
if (delim == "}") {
break;
}
parseField(
keyTypeId,
keyValSplit.first,
tokenizerCopy,
static_cast<ProtocolWriter*>(nullptr));
if (tokenizerCopy.getNextToken() != ":") {
throw TProtocolException(
TProtocolException::INVALID_DATA, "Missing : delimiter");
}
parseField(
valTypeId,
keyValSplit.second,
tokenizerCopy,
static_cast<ProtocolWriter*>(nullptr));
numElems++;
}
if (outProtoWriter) {
outProtoWriter->writeMapBegin(keyTypeId, valTypeId, numElems);
}
// Now, go back and actually parse the map.
for (size_t i = 0; i < numElems; ++i) {
parseField(keyTypeId, keyValSplit.first, tokenizer, outProtoWriter);
if (getNextOrThrow() != ":") {
throw TProtocolException(
TProtocolException::INVALID_DATA, "Missing : delimiter");
}
parseField(valTypeId, keyValSplit.second, tokenizer, outProtoWriter);
}
if (getNextOrThrow() != "}") {
throw TProtocolException(
TProtocolException::INVALID_DATA, "Missing } delimiter");
}
if (outProtoWriter) {
outProtoWriter->writeMapEnd();
}
break;
}
default:
TProtocolException::throwInvalidSkipType(expectedType);
break;
}
}