/Users/deen/code/yugabyte-db/src/yb/gen_yrpc/substitutions.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) YugaByte, Inc. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
4 | | // in compliance with the License. You may obtain a copy of the License at |
5 | | // |
6 | | // http://www.apache.org/licenses/LICENSE-2.0 |
7 | | // |
8 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
9 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
10 | | // or implied. See the License for the specific language governing permissions and limitations |
11 | | // under the License. |
12 | | // |
13 | | |
14 | | #include "yb/gen_yrpc/substitutions.h" |
15 | | |
16 | | #include <boost/algorithm/string/case_conv.hpp> |
17 | | |
18 | | #include <google/protobuf/descriptor.h> |
19 | | #include <google/protobuf/descriptor.pb.h> |
20 | | |
21 | | #include "yb/gen_yrpc/model.h" |
22 | | |
23 | | #include "yb/gutil/strings/util.h" |
24 | | #include "yb/gutil/strings/split.h" |
25 | | |
26 | | #include "yb/rpc/service.pb.h" |
27 | | |
28 | | #include "yb/util/format.h" |
29 | | |
30 | | namespace yb { |
31 | | namespace gen_yrpc { |
32 | | |
33 | | namespace { |
34 | | |
35 | | const std::string kWireFormat = "::google::protobuf::internal::WireFormatLite"; |
36 | | |
37 | | // Extract the last filename component. |
38 | 0 | std::string GetBaseName(const std::string &path) { |
39 | 0 | size_t last_slash = path.find_last_of("/"); |
40 | 0 | return last_slash != string::npos ? path.substr(last_slash + 1) : path; |
41 | 0 | } |
42 | | |
43 | 0 | std::string GenerateOpenNamespace(const std::string& str) { |
44 | 0 | std::string out; |
45 | 0 | for (const auto c : strings::Split(str, ".")) { |
46 | 0 | out += Format("namespace $0 {\n", c); |
47 | 0 | } |
48 | 0 | return out; |
49 | 0 | } |
50 | | |
51 | 0 | std::string GenerateCloseNamespace(const string &str) { |
52 | 0 | std::string out; |
53 | 0 | for (const auto c : strings::Split(str, ".")) { |
54 | 0 | out = Format("} // namespace $0\n", c) + out; |
55 | 0 | } |
56 | 0 | return out; |
57 | 0 | } |
58 | | |
59 | | } // namespace |
60 | | |
61 | | FileSubstitutions::FileSubstitutions(const google::protobuf::FileDescriptor* file) |
62 | 0 | : file_(file), path_no_extension_(RemoveProtoExtension(file->name())) { |
63 | 0 | } |
64 | | |
65 | 0 | Substitutions FileSubstitutions::Create() { |
66 | 0 | std::string path = file_->name(); |
67 | 0 | Substitutions result; |
68 | |
|
69 | 0 | result.emplace_back("path", path); |
70 | 0 | result.emplace_back("path_no_extension", path_no_extension_); |
71 | | |
72 | | // If path = /foo/bar/baz_stuff.proto, base_ = baz_stuff |
73 | 0 | result.emplace_back("base", GetBaseName(path_no_extension_)); |
74 | | |
75 | | // If path = /foo/bar/baz_stuff.proto, upper_case_ = BAZ_STUFF |
76 | 0 | std::string upper_case = boost::to_upper_copy(path_no_extension_); |
77 | 0 | std::replace(upper_case.begin(), upper_case.end(), '/', '_'); |
78 | 0 | result.emplace_back("upper_case", upper_case); |
79 | |
|
80 | 0 | result.emplace_back("open_namespace", GenerateOpenNamespace(file_->package())); |
81 | 0 | result.emplace_back("close_namespace", GenerateCloseNamespace(file_->package())); |
82 | |
|
83 | 0 | result.emplace_back("wire_format", kWireFormat); |
84 | |
|
85 | 0 | return result; |
86 | 0 | } |
87 | | |
88 | 0 | Substitutions CreateSubstitutions(const google::protobuf::Descriptor* message) { |
89 | 0 | Substitutions result; |
90 | 0 | auto message_name = UnnestedName(message, Lightweight::kFalse, false); |
91 | 0 | result.emplace_back("message_name", message_name); |
92 | 0 | std::string message_pb_name; |
93 | 0 | if (IsLwAny(message)) { |
94 | 0 | message_pb_name = "::google::protobuf::Any"; |
95 | 0 | } else if (message->options().map_entry()) { |
96 | 0 | auto key_type = MapFieldType(message->FindFieldByName("key"), Lightweight::kFalse); |
97 | 0 | auto value_type = MapFieldType(message->FindFieldByName("value"), Lightweight::kFalse); |
98 | 0 | message_pb_name = "::google::protobuf::MapPair<" + key_type + ", " + value_type + ">"; |
99 | 0 | } else { |
100 | 0 | message_pb_name = message_name; |
101 | 0 | } |
102 | 0 | result.emplace_back("message_pb_name", message_pb_name); |
103 | 0 | result.emplace_back("message_lw_name", UnnestedName(message, Lightweight::kTrue, false)); |
104 | 0 | uint32 max_tag = 0; |
105 | 0 | for (int i = 0; i != message->field_count(); ++i) { |
106 | 0 | auto* field = message->field(i); |
107 | 0 | auto wire_type = WireType(field); |
108 | 0 | max_tag = std::max( |
109 | 0 | max_tag, google::protobuf::internal::WireFormatLite::MakeTag(field->number(), wire_type)); |
110 | 0 | } |
111 | |
|
112 | 0 | uint32_t cutoff = 1; |
113 | 0 | while (cutoff < max_tag) { |
114 | 0 | cutoff = cutoff * 2 + 1; |
115 | 0 | } |
116 | 0 | result.emplace_back("cutoff", std::to_string(cutoff)); |
117 | 0 | return result; |
118 | 0 | } |
119 | | |
120 | | Substitutions CreateSubstitutions( |
121 | 0 | const google::protobuf::MethodDescriptor* method, rpc::RpcSides side) { |
122 | 0 | Substitutions result; |
123 | |
|
124 | 0 | result.emplace_back("rpc_name", method->name()); |
125 | 0 | result.emplace_back("rpc_full_name", method->full_name()); |
126 | 0 | result.emplace_back("rpc_full_name_plainchars", |
127 | 0 | StringReplace(method->full_name(), ".", "_", true)); |
128 | |
|
129 | 0 | auto request_type = method->input_type()->full_name(); |
130 | 0 | auto response_type = method->output_type()->full_name(); |
131 | 0 | if (IsLightweightMethod(method, side)) { |
132 | 0 | request_type = MakeLightweightName(request_type); |
133 | 0 | response_type = MakeLightweightName(response_type); |
134 | 0 | result.emplace_back("params", "RpcCallLWParams"); |
135 | 0 | } else { |
136 | 0 | result.emplace_back("params", "RpcCallPBParams"); |
137 | 0 | } |
138 | 0 | result.emplace_back("request", RelativeClassPath(request_type, method->service()->full_name())); |
139 | 0 | result.emplace_back( |
140 | 0 | "response", RelativeClassPath(response_type, method->service()->full_name())); |
141 | 0 | result.emplace_back("metric_enum_key", Format("k$0", method->name())); |
142 | |
|
143 | 0 | return result; |
144 | 0 | } |
145 | | |
146 | 0 | Substitutions CreateSubstitutions(const google::protobuf::FieldDescriptor* field) { |
147 | 0 | Substitutions result; |
148 | 0 | auto field_name = boost::to_lower_copy(field->name()); |
149 | 0 | result.emplace_back("field_name", field_name); |
150 | 0 | result.emplace_back("field_value", field->is_repeated() ? "entry" : field_name + "()"); |
151 | 0 | auto camelcase_name = field->camelcase_name(); |
152 | 0 | camelcase_name[0] = std::toupper(camelcase_name[0]); |
153 | 0 | result.emplace_back("field_camelcase_name", camelcase_name); |
154 | 0 | std::string field_type = MapFieldType(field, Lightweight::kTrue); |
155 | 0 | const char* message_type_format = "::yb::ArenaList<$0>"; |
156 | 0 | result.emplace_back( |
157 | 0 | "field_stored_type", |
158 | 0 | field->is_repeated() |
159 | 0 | ? Format(IsMessage(field) ? message_type_format : "::yb::MCVector<$0>", field_type) |
160 | 0 | : field_type); |
161 | 0 | result.emplace_back("field_type", field_type); |
162 | 0 | result.emplace_back("nonlw_field_type", MapFieldType(field, Lightweight::kFalse)); |
163 | 0 | auto field_type_name = "TYPE_" + boost::to_upper_copy(std::string(field->type_name())); |
164 | 0 | result.emplace_back("field_type_name", field_type_name); |
165 | 0 | result.emplace_back("field_number", std::to_string(field->number())); |
166 | 0 | result.emplace_back( |
167 | 0 | "field_serialization", |
168 | 0 | Format("::yb::rpc::LightweightSerialization<$0::$1, $2>", |
169 | 0 | kWireFormat, field_type_name, field_type)); |
170 | 0 | result.emplace_back( |
171 | 0 | "field_serialization_prefix", |
172 | 0 | field->is_packed() ? "Packed" : field->is_repeated() ? "Repeated" : "Single"); |
173 | 0 | return result; |
174 | 0 | } |
175 | | |
176 | 0 | Substitutions CreateSubstitutions(const google::protobuf::ServiceDescriptor* service) { |
177 | 0 | Substitutions result; |
178 | 0 | result.emplace_back("service_name", service->name()); |
179 | 0 | std::string full_service_name = service->full_name(); |
180 | 0 | result.emplace_back("original_full_service_name", full_service_name); |
181 | 0 | auto custom_service_name = service->options().GetExtension(rpc::custom_service_name); |
182 | 0 | if (!custom_service_name.empty()) { |
183 | 0 | full_service_name = custom_service_name; |
184 | 0 | } |
185 | 0 | result.emplace_back("full_service_name", full_service_name); |
186 | 0 | result.emplace_back("service_method_count", std::to_string(service->method_count())); |
187 | 0 | result.emplace_back("service_method_enum", service->name() + "RpcMethodIndexes"); |
188 | | |
189 | | // TODO: upgrade to protobuf 2.5.x and attach service comments |
190 | | // to the generated service classes using the SourceLocation API. |
191 | 0 | return result; |
192 | 0 | } |
193 | | |
194 | | } // namespace gen_yrpc |
195 | | } // namespace yb |