1/*
2 *
3 * Copyright 2019 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19#ifndef GRPC_INTERNAL_COMPILER_CPP_PLUGIN_H
20#define GRPC_INTERNAL_COMPILER_CPP_PLUGIN_H
21
22#include <memory>
23#include <sstream>
24
25#include "src/compiler/config.h"
26
27#include "src/compiler/cpp_generator.h"
28#include "src/compiler/generator_helpers.h"
29#include "src/compiler/protobuf_plugin.h"
30
31// Cpp Generator for Protobug IDL
32class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator {
33 public:
34 CppGrpcGenerator() {}
35 virtual ~CppGrpcGenerator() {}
36
37 virtual bool Generate(const grpc::protobuf::FileDescriptor* file,
38 const grpc::string& parameter,
39 grpc::protobuf::compiler::GeneratorContext* context,
40 grpc::string* error) const {
41 if (file->options().cc_generic_services()) {
42 *error =
43 "cpp grpc proto compiler plugin does not work with generic "
44 "services. To generate cpp grpc APIs, please set \""
45 "cc_generic_service = false\".";
46 return false;
47 }
48
49 grpc_cpp_generator::Parameters generator_parameters;
50 generator_parameters.use_system_headers = true;
51 generator_parameters.generate_mock_code = false;
52 generator_parameters.include_import_headers = false;
53
54 ProtoBufFile pbfile(file);
55
56 if (!parameter.empty()) {
57 std::vector<grpc::string> parameters_list =
58 grpc_generator::tokenize(parameter, ",");
59 for (auto parameter_string = parameters_list.begin();
60 parameter_string != parameters_list.end(); parameter_string++) {
61 std::vector<grpc::string> param =
62 grpc_generator::tokenize(*parameter_string, "=");
63 if (param[0] == "services_namespace") {
64 generator_parameters.services_namespace = param[1];
65 } else if (param[0] == "use_system_headers") {
66 if (param[1] == "true") {
67 generator_parameters.use_system_headers = true;
68 } else if (param[1] == "false") {
69 generator_parameters.use_system_headers = false;
70 } else {
71 *error = grpc::string("Invalid parameter: ") + *parameter_string;
72 return false;
73 }
74 } else if (param[0] == "grpc_search_path") {
75 generator_parameters.grpc_search_path = param[1];
76 } else if (param[0] == "generate_mock_code") {
77 if (param[1] == "true") {
78 generator_parameters.generate_mock_code = true;
79 } else if (param[1] != "false") {
80 *error = grpc::string("Invalid parameter: ") + *parameter_string;
81 return false;
82 }
83 } else if (param[0] == "gmock_search_path") {
84 generator_parameters.gmock_search_path = param[1];
85 } else if (param[0] == "additional_header_includes") {
86 generator_parameters.additional_header_includes =
87 grpc_generator::tokenize(param[1], ":");
88 } else if (param[0] == "message_header_extension") {
89 generator_parameters.message_header_extension = param[1];
90 } else if (param[0] == "include_import_headers") {
91 if (param[1] == "true") {
92 generator_parameters.include_import_headers = true;
93 } else if (param[1] != "false") {
94 *error = grpc::string("Invalid parameter: ") + *parameter_string;
95 return false;
96 }
97 } else {
98 *error = grpc::string("Unknown parameter: ") + *parameter_string;
99 return false;
100 }
101 }
102 }
103
104 grpc::string file_name = grpc_generator::StripProto(file->name());
105
106 grpc::string header_code =
107 grpc_cpp_generator::GetHeaderPrologue(&pbfile, generator_parameters) +
108 grpc_cpp_generator::GetHeaderIncludes(&pbfile, generator_parameters) +
109 grpc_cpp_generator::GetHeaderServices(&pbfile, generator_parameters) +
110 grpc_cpp_generator::GetHeaderEpilogue(&pbfile, generator_parameters);
111 std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> header_output(
112 context->Open(file_name + ".grpc.pb.h"));
113 grpc::protobuf::io::CodedOutputStream header_coded_out(header_output.get());
114 header_coded_out.WriteRaw(header_code.data(), header_code.size());
115
116 grpc::string source_code =
117 grpc_cpp_generator::GetSourcePrologue(&pbfile, generator_parameters) +
118 grpc_cpp_generator::GetSourceIncludes(&pbfile, generator_parameters) +
119 grpc_cpp_generator::GetSourceServices(&pbfile, generator_parameters) +
120 grpc_cpp_generator::GetSourceEpilogue(&pbfile, generator_parameters);
121 std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> source_output(
122 context->Open(file_name + ".grpc.pb.cc"));
123 grpc::protobuf::io::CodedOutputStream source_coded_out(source_output.get());
124 source_coded_out.WriteRaw(source_code.data(), source_code.size());
125
126 if (!generator_parameters.generate_mock_code) {
127 return true;
128 }
129 grpc::string mock_code =
130 grpc_cpp_generator::GetMockPrologue(&pbfile, generator_parameters) +
131 grpc_cpp_generator::GetMockIncludes(&pbfile, generator_parameters) +
132 grpc_cpp_generator::GetMockServices(&pbfile, generator_parameters) +
133 grpc_cpp_generator::GetMockEpilogue(&pbfile, generator_parameters);
134 std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> mock_output(
135 context->Open(file_name + "_mock.grpc.pb.h"));
136 grpc::protobuf::io::CodedOutputStream mock_coded_out(mock_output.get());
137 mock_coded_out.WriteRaw(mock_code.data(), mock_code.size());
138
139 return true;
140 }
141
142 private:
143 // Insert the given code into the given file at the given insertion point.
144 void Insert(grpc::protobuf::compiler::GeneratorContext* context,
145 const grpc::string& filename, const grpc::string& insertion_point,
146 const grpc::string& code) const {
147 std::unique_ptr<grpc::protobuf::io::ZeroCopyOutputStream> output(
148 context->OpenForInsert(filename, insertion_point));
149 grpc::protobuf::io::CodedOutputStream coded_out(output.get());
150 coded_out.WriteRaw(code.data(), code.size());
151 }
152};
153
154#endif // GRPC_INTERNAL_COMPILER_CPP_PLUGIN_H
155