Skip to content

Commit 4823bbf

Browse files
iahsfacebook-github-bot
authored andcommitted
Populate struct fields
Summary: Fills in https://github.com/facebook/fbthrift/blob/main/thrift/lib/thrift/schema.thrift for opted-in structs Reviewed By: vitaut Differential Revision: D38715716 fbshipit-source-id: 65398d18069477e0fb0e80503eb4d38e99ef8b7f
1 parent 786fad1 commit 4823bbf

File tree

3 files changed

+200
-21
lines changed

3 files changed

+200
-21
lines changed

third-party/thrift/src/thrift/compiler/lib/schematizer.cc

Lines changed: 147 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,36 +14,165 @@
1414
* limitations under the License.
1515
*/
1616

17+
#include <thrift/compiler/ast/t_exception.h>
18+
#include <thrift/compiler/ast/t_program.h>
19+
#include <thrift/compiler/ast/t_union.h>
1720
#include <thrift/compiler/lib/schematizer.h>
1821

1922
namespace apache {
2023
namespace thrift {
2124
namespace compiler {
22-
std::unique_ptr<t_const_value> schematizer::gen_schema(
23-
const t_structured& node) {
24-
auto schema = std::make_unique<t_const_value>();
25-
schema->set_map();
25+
namespace {
26+
template <typename... Args>
27+
std::unique_ptr<t_const_value> val(Args... args) {
28+
return std::make_unique<t_const_value>(std::forward<Args>(args)...);
29+
}
2630

27-
// Definition
28-
auto definition = std::make_unique<t_const_value>();
31+
void add_definition(t_const_value& schema, const t_named& node) {
32+
auto definition = val();
2933
definition->set_map();
30-
definition->add_map(
31-
std::make_unique<t_const_value>("name"),
32-
std::make_unique<t_const_value>(node.name()));
33-
definition->add_map(
34-
std::make_unique<t_const_value>("uri"),
35-
std::make_unique<t_const_value>(node.uri()));
34+
definition->add_map(val("name"), val(node.name()));
35+
if (!node.uri().empty()) {
36+
definition->add_map(val("uri"), val(node.uri()));
37+
}
3638
// TODO: annotations
37-
schema->add_map(
38-
std::make_unique<t_const_value>("definition"), std::move(definition));
39+
schema.add_map(val("definition"), std::move(definition));
40+
}
41+
42+
std::unique_ptr<t_const_value> gen_type(const t_type& type) {
43+
auto schema = val();
44+
schema->set_map();
45+
auto type_name = val();
46+
type_name->set_map();
47+
std::unique_ptr<t_const_value> params;
48+
switch (type.get_type_value()) {
49+
case t_type::type::t_bool:
50+
type_name->add_map(val("boolType"), val(0));
51+
break;
52+
case t_type::type::t_byte:
53+
type_name->add_map(val("byteType"), val(0));
54+
break;
55+
case t_type::type::t_i16:
56+
type_name->add_map(val("i16Type"), val(0));
57+
break;
58+
case t_type::type::t_i32:
59+
type_name->add_map(val("i32Type"), val(0));
60+
break;
61+
case t_type::type::t_i64:
62+
type_name->add_map(val("i64Type"), val(0));
63+
break;
64+
case t_type::type::t_double:
65+
type_name->add_map(val("doubleType"), val(0));
66+
break;
67+
case t_type::type::t_float:
68+
type_name->add_map(val("floatType"), val(0));
69+
break;
70+
case t_type::type::t_string:
71+
type_name->add_map(val("stringType"), val(0));
72+
break;
73+
case t_type::type::t_binary:
74+
type_name->add_map(val("binaryType"), val(0));
75+
break;
76+
case t_type::type::t_list:
77+
type_name->add_map(val("listType"), val(0));
78+
params = val();
79+
params->set_list();
80+
params->add_list(gen_type(
81+
*static_cast<const t_list&>(type).elem_type()->get_true_type()));
82+
break;
83+
case t_type::type::t_set:
84+
type_name->add_map(val("setType"), val(0));
85+
params = val();
86+
params->set_list();
87+
params->add_list(gen_type(
88+
*static_cast<const t_set&>(type).elem_type()->get_true_type()));
89+
break;
90+
case t_type::type::t_map:
91+
type_name->add_map(val("mapType"), val(0));
92+
params = val();
93+
params->set_list();
94+
{
95+
const auto& map = static_cast<const t_map&>(type);
96+
params->add_list(gen_type(*map.key_type()->get_true_type()));
97+
params->add_list(gen_type(*map.val_type()->get_true_type()));
98+
}
99+
break;
100+
case t_type::type::t_enum:
101+
type_name->add_map(val("enumType"), val(type.uri()));
102+
break;
103+
case t_type::type::t_struct:
104+
type_name->add_map(
105+
val([&] {
106+
if (dynamic_cast<const t_union*>(&type)) {
107+
return "unionType";
108+
} else if (dynamic_cast<const t_exception*>(&type)) {
109+
return "exceptionType";
110+
} else {
111+
return "structType";
112+
}
113+
}()),
114+
val(type.uri()));
115+
break;
116+
default:
117+
assert(false);
118+
}
119+
schema->add_map(val("name"), std::move(type_name));
120+
if (params) {
121+
schema->add_map(val("params"), std::move(params));
122+
}
123+
return schema;
124+
}
125+
} // namespace
126+
127+
std::unique_ptr<t_const_value> schematizer::gen_schema(
128+
const t_structured& node) {
129+
auto schema = val();
130+
schema->set_map();
131+
add_definition(*schema, node);
39132

40-
// Fields
41-
auto fields = std::make_unique<t_const_value>();
133+
auto fields = val();
42134
fields->set_list();
135+
// May be null in unit tests.
136+
const auto* program = node.program();
137+
const auto* field_qualifier_enum = program
138+
? dynamic_cast<const t_enum*>(program->scope()->find_def(
139+
"facebook.com/thrift/type/FieldQualifier"))
140+
: nullptr;
43141

44-
// TODO(iahs): fill in fields
142+
for (const auto& field : node.fields()) {
143+
auto field_schema = val();
144+
field_schema->set_map();
145+
add_definition(*field_schema, field);
146+
field_schema->add_map(val("id"), val(field.id()));
147+
auto qualifierVal = [&] {
148+
switch (field.qualifier()) {
149+
case t_field_qualifier::none:
150+
case t_field_qualifier::required:
151+
return 3; // Fill
152+
case t_field_qualifier::optional:
153+
return 1; // Optional
154+
case t_field_qualifier::terse:
155+
return 2; // Terse
156+
}
157+
assert(false);
158+
return 0; // Default
159+
}();
160+
auto qualifier = val();
161+
if (field_qualifier_enum) {
162+
qualifier->set_is_enum();
163+
qualifier->set_enum(field_qualifier_enum);
164+
qualifier->set_enum_value(field_qualifier_enum->find_value(qualifierVal));
165+
} else {
166+
qualifier->set_integer(qualifierVal);
167+
}
168+
field_schema->add_map(val("qualifier"), std::move(qualifier));
169+
field_schema->add_map(
170+
val("type"), gen_type(*field.type()->get_true_type()));
171+
// TODO: default
172+
fields->add_list(std::move(field_schema));
173+
}
45174

46-
schema->add_map(std::make_unique<t_const_value>("fields"), std::move(fields));
175+
schema->add_map(val("fields"), std::move(fields));
47176

48177
return schema;
49178
}

third-party/thrift/src/thrift/compiler/lib/schematizer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ namespace thrift {
2626
namespace compiler {
2727
class schematizer {
2828
public:
29+
// Creates a constant of type schema.Struct describing the argument.
30+
// https://github.com/facebook/fbthrift/blob/main/thrift/lib/thrift/schema.thrift
2931
static std::unique_ptr<t_const_value> gen_schema(const t_structured& node);
3032
};
3133
} // namespace compiler

third-party/thrift/src/thrift/compiler/lib/schematizer_test.cc

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
#include <unordered_map>
2020
#include <folly/portability/GTest.h>
21+
#include <thrift/compiler/ast/t_base_type.h>
22+
#include <thrift/compiler/ast/t_map.h>
2123
#include <thrift/compiler/ast/t_struct.h>
2224

2325
namespace apache::thrift::compiler {
@@ -29,8 +31,10 @@ std::unordered_map<std::string, t_const_value*> flatten_map(
2931
for (const auto& pair : val.get_map()) {
3032
map[pair.first->get_string()] = pair.second;
3133
}
32-
for (const auto& pair : map.at("definition")->get_map()) {
33-
map[pair.first->get_string()] = pair.second;
34+
if (auto def = map.find("definition"); def != map.end()) {
35+
for (const auto& pair : def->second->get_map()) {
36+
map[pair.first->get_string()] = pair.second;
37+
}
3438
}
3539
return map;
3640
}
@@ -39,6 +43,10 @@ std::unordered_map<std::string, t_const_value*> flatten_map(
3943
TEST(SchematizerTest, Structured) {
4044
t_struct s(nullptr, "Struct");
4145
s.set_uri("path/to/Struct");
46+
s.create_field(t_base_type::t_i16(), "i16", 1);
47+
s.create_field(s, "Struct", 2).set_qualifier(t_field_qualifier::optional);
48+
t_map tmap(t_base_type::t_string(), t_base_type::t_double());
49+
s.create_field(tmap, "Map", 3);
4250

4351
auto schema = schematizer::gen_schema(s);
4452
EXPECT_EQ(schema->get_type(), t_const_value::CV_MAP);
@@ -47,7 +55,47 @@ TEST(SchematizerTest, Structured) {
4755

4856
EXPECT_EQ(map.at("name")->get_string(), "Struct");
4957
EXPECT_EQ(map.at("uri")->get_string(), "path/to/Struct");
50-
EXPECT_EQ(fields.size(), 0);
58+
EXPECT_EQ(fields.size(), 3);
59+
60+
auto field1 = flatten_map(*fields.at(0));
61+
EXPECT_EQ(field1.at("id")->get_integer(), 1);
62+
EXPECT_EQ(field1.at("qualifier")->get_integer(), 3);
63+
EXPECT_EQ(field1.at("name")->get_string(), "i16");
64+
auto type1 = flatten_map(*field1.at("type"));
65+
EXPECT_EQ(type1.at("name")->get_map().at(0).first->get_string(), "i16Type");
66+
EXPECT_FALSE(type1.count("params"));
67+
68+
auto field2 = flatten_map(*fields.at(1));
69+
EXPECT_EQ(field2.at("id")->get_integer(), 2);
70+
EXPECT_EQ(field2.at("qualifier")->get_integer(), 1);
71+
EXPECT_EQ(field2.at("name")->get_string(), "Struct");
72+
auto type2 = flatten_map(*field2.at("type"));
73+
EXPECT_EQ(
74+
type2.at("name")->get_map().at(0).first->get_string(), "structType");
75+
EXPECT_EQ(
76+
type2.at("name")->get_map().at(0).second->get_string(), "path/to/Struct");
77+
EXPECT_FALSE(type2.count("params"));
78+
79+
auto field3 = flatten_map(*fields.at(2));
80+
EXPECT_EQ(field3.at("name")->get_string(), "Map");
81+
auto type3 = flatten_map(*field3.at("type"));
82+
EXPECT_EQ(type3.at("name")->get_map().at(0).first->get_string(), "mapType");
83+
auto params3 = type3.at("params")->get_list();
84+
EXPECT_EQ(params3.size(), 2);
85+
EXPECT_EQ(
86+
flatten_map(*params3.at(0))
87+
.at("name")
88+
->get_map()
89+
.at(0)
90+
.first->get_string(),
91+
"stringType");
92+
EXPECT_EQ(
93+
flatten_map(*params3.at(1))
94+
.at("name")
95+
->get_map()
96+
.at(0)
97+
.first->get_string(),
98+
"doubleType");
5199
}
52100

53101
} // namespace apache::thrift::compiler

0 commit comments

Comments
 (0)