1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 // Author: kenton@google.com (Kenton Varda)
9 // Based on original Protocol Buffers design by
10 // Sanjay Ghemawat, Jeff Dean, and others.
11
12 #include "google/protobuf/compiler/cpp/service.h"
13
14 #include <string>
15
16 #include "absl/strings/str_cat.h"
17 #include "google/protobuf/compiler/cpp/helpers.h"
18 #include "google/protobuf/descriptor.h"
19 #include "google/protobuf/io/printer.h"
20
21 namespace google {
22 namespace protobuf {
23 namespace compiler {
24 namespace cpp {
GenerateDeclarations(io::Printer * printer)25 void ServiceGenerator::GenerateDeclarations(io::Printer* printer) {
26 auto vars = printer->WithVars(&vars_);
27 printer->Emit(
28 {
29 {"virts", [&] { GenerateMethodSignatures(kVirtual, printer); }},
30 {"impls", [&] { GenerateMethodSignatures(kNonVirtual, printer); }},
31 },
32 R"cc(
33 class $classname$_Stub;
34 class $dllexport_decl $$classname$ : public ::$proto_ns$::Service {
35 protected:
36 $classname$() = default;
37
38 public:
39 using Stub = $classname$_Stub;
40
41 $classname$(const $classname$&) = delete;
42 $classname$& operator=(const $classname$&) = delete;
43 virtual ~$classname$() = default;
44
45 static const ::$proto_ns$::ServiceDescriptor* descriptor();
46
47 $virts$;
48
49 // implements Service ----------------------------------------------
50 const ::$proto_ns$::ServiceDescriptor* GetDescriptor() override;
51
52 void CallMethod(const ::$proto_ns$::MethodDescriptor* method,
53 ::$proto_ns$::RpcController* controller,
54 const ::$proto_ns$::Message* request,
55 ::$proto_ns$::Message* response,
56 ::google::protobuf::Closure* done) override;
57
58 const ::$proto_ns$::Message& GetRequestPrototype(
59 const ::$proto_ns$::MethodDescriptor* method) const override;
60
61 const ::$proto_ns$::Message& GetResponsePrototype(
62 const ::$proto_ns$::MethodDescriptor* method) const override;
63 };
64
65 class $dllexport_decl $$classname$_Stub final : public $classname$ {
66 public:
67 $classname$_Stub(::$proto_ns$::RpcChannel* channel);
68 $classname$_Stub(::$proto_ns$::RpcChannel* channel,
69 ::$proto_ns$::Service::ChannelOwnership ownership);
70
71 $classname$_Stub(const $classname$_Stub&) = delete;
72 $classname$_Stub& operator=(const $classname$_Stub&) = delete;
73
74 ~$classname$_Stub() override;
75
76 inline ::$proto_ns$::RpcChannel* channel() { return channel_; }
77
78 // implements $classname$ ------------------------------------------
79 $impls$;
80
81 private:
82 ::$proto_ns$::RpcChannel* channel_;
83 bool owns_channel_;
84 };
85 )cc");
86 }
87
GenerateMethodSignatures(VirtualOrNot virtual_or_not,io::Printer * printer)88 void ServiceGenerator::GenerateMethodSignatures(VirtualOrNot virtual_or_not,
89 io::Printer* printer) {
90 for (int i = 0; i < descriptor_->method_count(); ++i) {
91 const MethodDescriptor* method = descriptor_->method(i);
92
93 printer->Emit(
94 {
95 {"name", method->name()},
96 {"input", QualifiedClassName(method->input_type(), *options_)},
97 {"output", QualifiedClassName(method->output_type(), *options_)},
98 {"virtual", virtual_or_not == kVirtual ? "virtual" : ""},
99 {"override", virtual_or_not != kVirtual ? "override" : ""},
100 },
101 // No cc, clang-format does not format this string well due to the
102 // $ override$ substitution.
103 R"(
104 $virtual $void $name$(::$proto_ns$::RpcController* controller,
105 const $input$* request,
106 $output$* response,
107 ::google::protobuf::Closure* done)$ override$;
108 )");
109 }
110 }
111
112 // ===================================================================
113
GenerateImplementation(io::Printer * printer)114 void ServiceGenerator::GenerateImplementation(io::Printer* printer) {
115 auto vars = printer->WithVars(&vars_);
116 printer->Emit(
117 {
118 {"index", index_in_metadata_},
119 {"no_impl_methods", [&] { GenerateNotImplementedMethods(printer); }},
120 {"call_method", [&] { GenerateCallMethod(printer); }},
121 {"get_request", [&] { GenerateGetPrototype(kRequest, printer); }},
122 {"get_response", [&] { GenerateGetPrototype(kResponse, printer); }},
123 {"stub_methods", [&] { GenerateStubMethods(printer); }},
124 },
125 R"cc(
126 const ::$proto_ns$::ServiceDescriptor* $classname$::descriptor() {
127 ::$proto_ns$::internal::AssignDescriptors(&$desc_table$);
128 return $file_level_service_descriptors$[$index$];
129 }
130
131 const ::$proto_ns$::ServiceDescriptor* $classname$::GetDescriptor() {
132 return descriptor();
133 }
134
135 $no_impl_methods$;
136
137 $call_method$;
138
139 $get_request$;
140
141 $get_response$;
142
143 $classname$_Stub::$classname$_Stub(::$proto_ns$::RpcChannel* channel)
144 : channel_(channel), owns_channel_(false) {}
145
146 $classname$_Stub::$classname$_Stub(
147 ::$proto_ns$::RpcChannel* channel,
148 ::$proto_ns$::Service::ChannelOwnership ownership)
149 : channel_(channel),
150 owns_channel_(ownership ==
151 ::$proto_ns$::Service::STUB_OWNS_CHANNEL) {}
152
153 $classname$_Stub::~$classname$_Stub() {
154 if (owns_channel_) delete channel_;
155 }
156
157 $stub_methods$;
158 )cc");
159 }
160
GenerateNotImplementedMethods(io::Printer * printer)161 void ServiceGenerator::GenerateNotImplementedMethods(io::Printer* printer) {
162 for (int i = 0; i < descriptor_->method_count(); ++i) {
163 const MethodDescriptor* method = descriptor_->method(i);
164
165 printer->Emit(
166 {
167 {"name", method->name()},
168 {"input", QualifiedClassName(method->input_type(), *options_)},
169 {"output", QualifiedClassName(method->output_type(), *options_)},
170 },
171 R"cc(
172 void $classname$::$name$(::$proto_ns$::RpcController* controller,
173 const $input$*, $output$*, ::google::protobuf::Closure* done) {
174 controller->SetFailed("Method $name$() not implemented.");
175 done->Run();
176 }
177 )cc");
178 }
179 }
180
GenerateCallMethod(io::Printer * printer)181 void ServiceGenerator::GenerateCallMethod(io::Printer* printer) {
182 printer->Emit(
183 {
184 {"index", absl::StrCat(index_in_metadata_)},
185 {"cases", [&] { GenerateCallMethodCases(printer); }},
186 },
187 R"cc(
188 void $classname$::CallMethod(
189 const ::$proto_ns$::MethodDescriptor* method,
190 ::$proto_ns$::RpcController* controller,
191 const ::$proto_ns$::Message* request,
192 ::$proto_ns$::Message* response, ::google::protobuf::Closure* done) {
193 ABSL_DCHECK_EQ(method->service(), $file_level_service_descriptors$[$index$]);
194 switch (method->index()) {
195 $cases$;
196
197 default:
198 ABSL_LOG(FATAL) << "Bad method index; this should never happen.";
199 break;
200 }
201 }
202 )cc");
203 }
204
GenerateGetPrototype(RequestOrResponse which,io::Printer * printer)205 void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which,
206 io::Printer* printer) {
207 printer->Emit(
208 {
209 {"which", which == kRequest ? "Request" : "Response"},
210 {"which_type", which == kRequest ? "input" : "output"},
211 {"cases",
212 [&] {
213 for (int i = 0; i < descriptor_->method_count(); ++i) {
214 const MethodDescriptor* method = descriptor_->method(i);
215 const Descriptor* type = which == kRequest
216 ? method->input_type()
217 : method->output_type();
218
219 printer->Emit(
220 {
221 {"index", absl::StrCat(i)},
222 {"type", QualifiedClassName(type, *options_)},
223 },
224 R"cc(
225 case $index$:
226 return $type$::default_instance();
227 )cc");
228 }
229 }},
230 },
231 R"cc(
232 const ::$proto_ns$::Message& $classname$::Get$which$Prototype(
233 const ::$proto_ns$::MethodDescriptor* method) const {
234 ABSL_DCHECK_EQ(method->service(), descriptor());
235 switch (method->index()) {
236 $cases$;
237
238 default:
239 ABSL_LOG(FATAL) << "Bad method index; this should never happen.";
240 return *::$proto_ns$::MessageFactory::generated_factory()
241 ->GetPrototype(method->$which_type$_type());
242 }
243 }
244 )cc");
245 }
246
GenerateCallMethodCases(io::Printer * printer)247 void ServiceGenerator::GenerateCallMethodCases(io::Printer* printer) {
248 for (int i = 0; i < descriptor_->method_count(); ++i) {
249 const MethodDescriptor* method = descriptor_->method(i);
250 printer->Emit(
251 {
252 {"name", method->name()},
253 {"input", QualifiedClassName(method->input_type(), *options_)},
254 {"output", QualifiedClassName(method->output_type(), *options_)},
255 {"index", absl::StrCat(i)},
256 },
257 R"cc(
258 case $index$:
259 this->$name$(controller,
260 ::$proto_ns$::DownCastMessage<$input$>(request),
261 ::$proto_ns$::DownCastMessage<$output$>(response),
262 done);
263 break;
264 )cc");
265 }
266 }
267
GenerateStubMethods(io::Printer * printer)268 void ServiceGenerator::GenerateStubMethods(io::Printer* printer) {
269 for (int i = 0; i < descriptor_->method_count(); ++i) {
270 const MethodDescriptor* method = descriptor_->method(i);
271
272 printer->Emit(
273 {
274 {"name", method->name()},
275 {"input", QualifiedClassName(method->input_type(), *options_)},
276 {"output", QualifiedClassName(method->output_type(), *options_)},
277 {"index", absl::StrCat(i)},
278 },
279 R"cc(
280 void $classname$_Stub::$name$(::$proto_ns$::RpcController* controller,
281 const $input$* request,
282 $output$* response, ::google::protobuf::Closure* done) {
283 channel_->CallMethod(descriptor()->method($index$), controller,
284 request, response, done);
285 }
286 )cc");
287 }
288 }
289
290 } // namespace cpp
291 } // namespace compiler
292 } // namespace protobuf
293 } // namespace google
294