Skip to content

Commit

Permalink
Type::debugString
Browse files Browse the repository at this point in the history
Summary: An API to make it easy to debug Type instances. Will be used by AnyPatch  related utilities on top.

Reviewed By: Mizuchi

Differential Revision: D68046089

fbshipit-source-id: c78fd2284a2d1f172ffe6b00615b712863e09f7d
  • Loading branch information
Pranav Thulasiram Bhat authored and facebook-github-bot committed Jan 11, 2025
1 parent 9ec35af commit d9e0934
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 4 deletions.
92 changes: 92 additions & 0 deletions thrift/lib/cpp2/type/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include <thrift/lib/cpp2/type/Type.h>

#include <fmt/format.h>
#include <folly/lang/Exception.h>
#include <thrift/lib/cpp2/type/UniversalName.h>

Expand Down Expand Up @@ -174,4 +175,95 @@ bool identicalTypeStruct(const TypeStruct& lhs, const TypeStruct& rhs) {
}
}

namespace {

// meta.com/a/B -> B
std::string debugUri(std::string_view uri) {
auto pos = uri.find_last_of("/");
if (pos == std::string::npos) {
return "?";
} else {
return std::string(uri.begin() + pos + 1, uri.end());
}
}

// a.b.c.D -> D
std::string debugScopedName(std::string_view name) {
auto pos = name.find_last_of(".");
if (pos == std::string::npos) {
return "?";
} else {
return std::string(name.begin() + pos + 1, name.end());
}
}

std::string debugUri(const TypeUri& type) {
switch (type.getType()) {
case TypeUri::Type::uri:
return debugUri(*type.uri_ref());
case TypeUri::Type::scopedName:
return debugScopedName(*type.scopedName_ref());
case TypeUri::Type::typeHashPrefixSha2_256:
case TypeUri::Type::definitionKey:
// Need schema information!
return "?";
default:
folly::throw_exception<std::runtime_error>("Invalid type.");
}
}

std::string debugStringImpl(const TypeStruct& type) {
switch (type.name()->getType()) {
case TypeName::boolType:
return "bool";
case TypeName::byteType:
return "byte";
case TypeName::i16Type:
return "i16";
case TypeName::i32Type:
return "i32";
case TypeName::i64Type:
return "i64";
case TypeName::floatType:
return "float";
case TypeName::doubleType:
return "double";
case TypeName::stringType:
return "string";
case TypeName::binaryType:
return "binary";
case TypeName::enumType:
return fmt::format("enum<{}>", debugUri(*type.name()->enumType_ref()));
case TypeName::typedefType:
// Need schema to resolve :(
return fmt::format(
"typedef<{}>", debugUri(*type.name()->typedefType_ref()));
case TypeName::structType:
return fmt::format(
"struct<{}>", debugUri(*type.name()->structType_ref()));
case TypeName::unionType:
return fmt::format("union<{}>", debugUri(*type.name()->unionType_ref()));
case TypeName::exceptionType:
return fmt::format(
"exception<{}>", debugUri(*type.name()->exceptionType_ref()));
case TypeName::listType:
return fmt::format("list<{}>", debugStringImpl(type.params()->at(0)));
case TypeName::setType:
return fmt::format("set<{}>", debugStringImpl(type.params()->at(0)));
case TypeName::mapType:
return fmt::format(
"map<{}, {}>",
debugStringImpl(type.params()->at(0)),
debugStringImpl(type.params()->at(1)));
default:
folly::throw_exception<std::runtime_error>("Invalid type.");
}
}

} // namespace

std::string Type::debugString() const {
return debugStringImpl(toThrift());
}

} // namespace apache::thrift::type
5 changes: 5 additions & 0 deletions thrift/lib/cpp2/type/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ class Type : public detail::Wrap<TypeStruct> {
// parameters and have full, human-readable, Thrift URIs.
bool isValid() const { return isFull(data_, true, true); }

// Human readable string describing the type.
// DISCLAIMER: We provide NO guarantees of stability on the format used.
// DO NOT ATTEMPT TO PARSE THIS!!!
std::string debugString() const;

private:
static bool isFull(const TypeUri& typeUri, bool validate_uri);
static bool isFull(const TypeName& typeName, bool validate_uri);
Expand Down
38 changes: 34 additions & 4 deletions thrift/lib/cpp2/type/TypeTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,7 @@

#include <thrift/lib/cpp2/type/Type.h>

#include <list>
#include <stdexcept>
#include <unordered_map>
#include <unordered_set>
#include <vector>

#include <folly/portability/GTest.h>
#include <thrift/lib/cpp2/type/BaseType.h>
Expand Down Expand Up @@ -301,5 +297,39 @@ TEST(TypeTest, IdenticalTypeStructHash) {
}
}

TEST(TypeTest, DebugString) {
TypeStruct scopedStruct;
scopedStruct.name()->structType_ref().emplace().scopedName_ref() =
"foo.bar.Baz";

TypeStruct hashedUnion;
hashedUnion.name()->unionType_ref().emplace().typeHashPrefixSha2_256_ref() =
"\x00\x01\x02\x03";

TypeStruct keyedEnum;
keyedEnum.name()->enumType_ref().emplace().definitionKey_ref() = "abcde";

auto testCases = std::list<std::pair<Type, std::string>>{
{Type::get<bool_t>(), "bool"},
{Type::get<string_t>(), "string"},
{Type::get<list<i64_t>>(), "list<i64>"},
{Type::get<map<i32_t, double_t>>(), "map<i32, double>"},
{Type::create<struct_c>("meta.com/foo/Bar"), "struct<Bar>"},
{Type(scopedStruct), "struct<Baz>"},
{Type(hashedUnion), "union<?>"},
{Type(keyedEnum), "enum<?>"},
{Type(
map_c{},
Type::get<i16_t>(),
Type::create<struct_c>("meta.com/foo/Bar")),
"map<i16, struct<Bar>>"},
};

for (const auto& [type, expected] : testCases) {
EXPECT_EQ(type.debugString(), expected);
}

EXPECT_THROW(Type().debugString(), std::runtime_error);
}
} // namespace
} // namespace apache::thrift::type

0 comments on commit d9e0934

Please sign in to comment.