| // Protocol Buffers - Google's data interchange format |
| // Copyright 2008 Google Inc. All rights reserved. |
| // https://developers.google.com/protocol-buffers/ |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| // Author: kenton@google.com (Kenton Varda) |
| // Based on original Protocol Buffers design by |
| // Sanjay Ghemawat, Jeff Dean, and others. |
| |
| #include "google/protobuf/compiler/cpp/service.h" |
| |
| #include <string> |
| |
| #include "absl/strings/str_cat.h" |
| #include "google/protobuf/compiler/cpp/helpers.h" |
| #include "google/protobuf/io/printer.h" |
| |
| namespace google { |
| namespace protobuf { |
| namespace compiler { |
| namespace cpp { |
| void ServiceGenerator::GenerateDeclarations(io::Printer* printer) { |
| auto vars = printer->WithVars(&vars_); |
| printer->Emit( |
| { |
| {"virts", [&] { GenerateMethodSignatures(kVirtual, printer); }}, |
| {"impls", [&] { GenerateMethodSignatures(kNonVirtual, printer); }}, |
| }, |
| R"cc( |
| class $classname$_Stub; |
| class $dllexport_decl $$classname$ : public ::$proto_ns$::Service { |
| protected: |
| $classname$() = default; |
| |
| public: |
| using Stub = $classname$_Stub; |
| |
| $classname$(const $classname$&) = delete; |
| $classname$& operator=(const $classname$&) = delete; |
| virtual ~$classname$() = default; |
| |
| static const ::$proto_ns$::ServiceDescriptor* descriptor(); |
| |
| $virts$; |
| |
| // implements Service ---------------------------------------------- |
| const ::$proto_ns$::ServiceDescriptor* GetDescriptor() override; |
| |
| void CallMethod(const ::$proto_ns$::MethodDescriptor* method, |
| ::$proto_ns$::RpcController* controller, |
| const ::$proto_ns$::Message* request, |
| ::$proto_ns$::Message* response, |
| ::google::protobuf::Closure* done) override; |
| |
| const ::$proto_ns$::Message& GetRequestPrototype( |
| const ::$proto_ns$::MethodDescriptor* method) const override; |
| |
| const ::$proto_ns$::Message& GetResponsePrototype( |
| const ::$proto_ns$::MethodDescriptor* method) const override; |
| }; |
| |
| class $dllexport_decl $$classname$_Stub final : public $classname$ { |
| public: |
| $classname$_Stub(::$proto_ns$::RpcChannel* channel); |
| $classname$_Stub(::$proto_ns$::RpcChannel* channel, |
| ::$proto_ns$::Service::ChannelOwnership ownership); |
| |
| $classname$_Stub(const $classname$_Stub&) = delete; |
| $classname$_Stub& operator=(const $classname$_Stub&) = delete; |
| |
| ~$classname$_Stub() override; |
| |
| inline ::$proto_ns$::RpcChannel* channel() { return channel_; } |
| |
| // implements $classname$ ------------------------------------------ |
| $impls$; |
| |
| private: |
| ::$proto_ns$::RpcChannel* channel_; |
| bool owns_channel_; |
| }; |
| )cc"); |
| } |
| |
| void ServiceGenerator::GenerateMethodSignatures(VirtualOrNot virtual_or_not, |
| io::Printer* printer) { |
| for (int i = 0; i < descriptor_->method_count(); ++i) { |
| const MethodDescriptor* method = descriptor_->method(i); |
| |
| printer->Emit( |
| { |
| {"name", method->name()}, |
| {"input", QualifiedClassName(method->input_type(), *options_)}, |
| {"output", QualifiedClassName(method->output_type(), *options_)}, |
| {"virtual", virtual_or_not == kVirtual ? "virtual" : ""}, |
| {"override", virtual_or_not != kVirtual ? "override" : ""}, |
| }, |
| // No cc, clang-format does not format this string well due to the |
| // $ override$ substitution. |
| R"( |
| $virtual $void $name$(::$proto_ns$::RpcController* controller, |
| const $input$* request, |
| $output$* response, |
| ::google::protobuf::Closure* done)$ override$; |
| )"); |
| } |
| } |
| |
| // =================================================================== |
| |
| void ServiceGenerator::GenerateImplementation(io::Printer* printer) { |
| auto vars = printer->WithVars(&vars_); |
| printer->Emit( |
| { |
| {"index", index_in_metadata_}, |
| {"no_impl_methods", [&] { GenerateNotImplementedMethods(printer); }}, |
| {"call_method", [&] { GenerateCallMethod(printer); }}, |
| {"get_request", [&] { GenerateGetPrototype(kRequest, printer); }}, |
| {"get_response", [&] { GenerateGetPrototype(kResponse, printer); }}, |
| {"stub_methods", [&] { GenerateStubMethods(printer); }}, |
| }, |
| R"cc( |
| const ::$proto_ns$::ServiceDescriptor* $classname$::descriptor() { |
| ::$proto_ns$::internal::AssignDescriptors(&$desc_table$); |
| return $file_level_service_descriptors$[$index$]; |
| } |
| |
| const ::$proto_ns$::ServiceDescriptor* $classname$::GetDescriptor() { |
| return descriptor(); |
| } |
| |
| $no_impl_methods$; |
| |
| $call_method$; |
| |
| $get_request$; |
| |
| $get_response$; |
| |
| $classname$_Stub::$classname$_Stub(::$proto_ns$::RpcChannel* channel) |
| : channel_(channel), owns_channel_(false) {} |
| |
| $classname$_Stub::$classname$_Stub( |
| ::$proto_ns$::RpcChannel* channel, |
| ::$proto_ns$::Service::ChannelOwnership ownership) |
| : channel_(channel), |
| owns_channel_(ownership == |
| ::$proto_ns$::Service::STUB_OWNS_CHANNEL) {} |
| |
| $classname$_Stub::~$classname$_Stub() { |
| if (owns_channel_) delete channel_; |
| } |
| |
| $stub_methods$; |
| )cc"); |
| } |
| |
| void ServiceGenerator::GenerateNotImplementedMethods(io::Printer* printer) { |
| for (int i = 0; i < descriptor_->method_count(); ++i) { |
| const MethodDescriptor* method = descriptor_->method(i); |
| |
| printer->Emit( |
| { |
| {"name", method->name()}, |
| {"input", QualifiedClassName(method->input_type(), *options_)}, |
| {"output", QualifiedClassName(method->output_type(), *options_)}, |
| }, |
| R"cc( |
| void $classname$::$name$(::$proto_ns$::RpcController* controller, |
| const $input$*, $output$*, ::google::protobuf::Closure* done) { |
| controller->SetFailed("Method $name$() not implemented."); |
| done->Run(); |
| } |
| )cc"); |
| } |
| } |
| |
| void ServiceGenerator::GenerateCallMethod(io::Printer* printer) { |
| printer->Emit( |
| { |
| {"index", absl::StrCat(index_in_metadata_)}, |
| {"cases", [&] { GenerateCallMethodCases(printer); }}, |
| }, |
| R"cc( |
| void $classname$::CallMethod( |
| const ::$proto_ns$::MethodDescriptor* method, |
| ::$proto_ns$::RpcController* controller, |
| const ::$proto_ns$::Message* request, |
| ::$proto_ns$::Message* response, ::google::protobuf::Closure* done) { |
| GOOGLE_DCHECK_EQ(method->service(), $file_level_service_descriptors$[$index$]); |
| switch (method->index()) { |
| $cases$; |
| |
| default: |
| GOOGLE_LOG(FATAL) << "Bad method index; this should never happen."; |
| break; |
| } |
| } |
| )cc"); |
| } |
| |
| void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which, |
| io::Printer* printer) { |
| printer->Emit( |
| { |
| {"which", which == kRequest ? "Request" : "Response"}, |
| {"which_type", which == kRequest ? "input" : "output"}, |
| {"cases", |
| [&] { |
| for (int i = 0; i < descriptor_->method_count(); ++i) { |
| const MethodDescriptor* method = descriptor_->method(i); |
| const Descriptor* type = which == kRequest |
| ? method->input_type() |
| : method->output_type(); |
| |
| printer->Emit( |
| { |
| {"index", absl::StrCat(i)}, |
| {"type", QualifiedClassName(type, *options_)}, |
| }, |
| R"cc( |
| case $index$: |
| return $type$::default_instance(); |
| )cc"); |
| } |
| }}, |
| }, |
| R"cc( |
| const ::$proto_ns$::Message& $classname$::Get$which$Prototype( |
| const ::$proto_ns$::MethodDescriptor* method) const { |
| GOOGLE_DCHECK_EQ(method->service(), descriptor()); |
| switch (method->index()) { |
| $cases$; |
| |
| default: |
| GOOGLE_LOG(FATAL) << "Bad method index; this should never happen."; |
| return *::$proto_ns$::MessageFactory::generated_factory() |
| ->GetPrototype(method->$which_type$_type()); |
| } |
| } |
| )cc"); |
| } |
| |
| void ServiceGenerator::GenerateCallMethodCases(io::Printer* printer) { |
| for (int i = 0; i < descriptor_->method_count(); ++i) { |
| const MethodDescriptor* method = descriptor_->method(i); |
| printer->Emit( |
| { |
| {"name", method->name()}, |
| {"input", QualifiedClassName(method->input_type(), *options_)}, |
| {"output", QualifiedClassName(method->output_type(), *options_)}, |
| {"index", absl::StrCat(i)}, |
| }, |
| R"cc( |
| case $index$: |
| $name$(controller, |
| ::$proto_ns$::internal::DownCast<const $input$*>(request), |
| ::$proto_ns$::internal::DownCast<$output$*>(response), done); |
| break; |
| )cc"); |
| } |
| } |
| |
| void ServiceGenerator::GenerateStubMethods(io::Printer* printer) { |
| for (int i = 0; i < descriptor_->method_count(); ++i) { |
| const MethodDescriptor* method = descriptor_->method(i); |
| |
| printer->Emit( |
| { |
| {"name", method->name()}, |
| {"input", QualifiedClassName(method->input_type(), *options_)}, |
| {"output", QualifiedClassName(method->output_type(), *options_)}, |
| {"index", absl::StrCat(i)}, |
| }, |
| R"cc( |
| void $classname$_Stub::$name$(::$proto_ns$::RpcController* controller, |
| const $input$* request, |
| $output$* response, ::google::protobuf::Closure* done) { |
| channel_->CallMethod(descriptor()->method($index$), controller, |
| request, response, done); |
| } |
| )cc"); |
| } |
| } |
| |
| } // namespace cpp |
| } // namespace compiler |
| } // namespace protobuf |
| } // namespace google |