Imported Upstream version 1.18.0
[platform/upstream/grpc.git] / src / compiler / objective_c_generator.cc
1 /*
2  *
3  * Copyright 2015 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 #include <map>
20 #include <set>
21 #include <sstream>
22
23 #include "src/compiler/config.h"
24 #include "src/compiler/objective_c_generator.h"
25 #include "src/compiler/objective_c_generator_helpers.h"
26
27 #include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
28
29 using ::google::protobuf::compiler::objectivec::ClassName;
30 using ::grpc::protobuf::FileDescriptor;
31 using ::grpc::protobuf::FileDescriptor;
32 using ::grpc::protobuf::MethodDescriptor;
33 using ::grpc::protobuf::ServiceDescriptor;
34 using ::grpc::protobuf::io::Printer;
35 using ::std::map;
36 using ::std::set;
37
38 namespace grpc_objective_c_generator {
39 namespace {
40
41 void PrintProtoRpcDeclarationAsPragma(
42     Printer* printer, const MethodDescriptor* method,
43     map< ::grpc::string, ::grpc::string> vars) {
44   vars["client_stream"] = method->client_streaming() ? "stream " : "";
45   vars["server_stream"] = method->server_streaming() ? "stream " : "";
46
47   printer->Print(vars,
48                  "#pragma mark $method_name$($client_stream$$request_type$)"
49                  " returns ($server_stream$$response_type$)\n\n");
50 }
51
52 template <typename DescriptorType>
53 static void PrintAllComments(const DescriptorType* desc, Printer* printer) {
54   std::vector<grpc::string> comments;
55   grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_LEADING_DETACHED,
56                              &comments);
57   grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_LEADING,
58                              &comments);
59   grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_TRAILING,
60                              &comments);
61   if (comments.empty()) {
62     return;
63   }
64   printer->Print("/**\n");
65   for (auto it = comments.begin(); it != comments.end(); ++it) {
66     printer->Print(" * ");
67     size_t start_pos = it->find_first_not_of(' ');
68     if (start_pos != grpc::string::npos) {
69       printer->PrintRaw(it->c_str() + start_pos);
70     }
71     printer->Print("\n");
72   }
73   printer->Print(" */\n");
74 }
75
76 void PrintMethodSignature(Printer* printer, const MethodDescriptor* method,
77                           const map< ::grpc::string, ::grpc::string>& vars) {
78   // Print comment
79   PrintAllComments(method, printer);
80
81   printer->Print(vars, "- ($return_type$)$method_name$With");
82   if (method->client_streaming()) {
83     printer->Print("RequestsWriter:(GRXWriter *)requestWriter");
84   } else {
85     printer->Print(vars, "Request:($request_class$ *)request");
86   }
87
88   // TODO(jcanizales): Put this on a new line and align colons.
89   if (method->server_streaming()) {
90     printer->Print(vars,
91                    " eventHandler:(void(^)(BOOL done, "
92                    "$response_class$ *_Nullable response, NSError *_Nullable "
93                    "error))eventHandler");
94   } else {
95     printer->Print(vars,
96                    " handler:(void(^)($response_class$ *_Nullable response, "
97                    "NSError *_Nullable error))handler");
98   }
99 }
100
101 void PrintSimpleSignature(Printer* printer, const MethodDescriptor* method,
102                           map< ::grpc::string, ::grpc::string> vars) {
103   vars["method_name"] =
104       grpc_generator::LowercaseFirstLetter(vars["method_name"]);
105   vars["return_type"] = "void";
106   PrintMethodSignature(printer, method, vars);
107 }
108
109 void PrintAdvancedSignature(Printer* printer, const MethodDescriptor* method,
110                             map< ::grpc::string, ::grpc::string> vars) {
111   vars["method_name"] = "RPCTo" + vars["method_name"];
112   vars["return_type"] = "GRPCProtoCall *";
113   PrintMethodSignature(printer, method, vars);
114 }
115
116 inline map< ::grpc::string, ::grpc::string> GetMethodVars(
117     const MethodDescriptor* method) {
118   map< ::grpc::string, ::grpc::string> res;
119   res["method_name"] = method->name();
120   res["request_type"] = method->input_type()->name();
121   res["response_type"] = method->output_type()->name();
122   res["request_class"] = ClassName(method->input_type());
123   res["response_class"] = ClassName(method->output_type());
124   return res;
125 }
126
127 void PrintMethodDeclarations(Printer* printer, const MethodDescriptor* method) {
128   map< ::grpc::string, ::grpc::string> vars = GetMethodVars(method);
129
130   PrintProtoRpcDeclarationAsPragma(printer, method, vars);
131
132   PrintSimpleSignature(printer, method, vars);
133   printer->Print(";\n\n");
134   PrintAdvancedSignature(printer, method, vars);
135   printer->Print(";\n\n\n");
136 }
137
138 void PrintSimpleImplementation(Printer* printer, const MethodDescriptor* method,
139                                map< ::grpc::string, ::grpc::string> vars) {
140   printer->Print("{\n");
141   printer->Print(vars, "  [[self RPCTo$method_name$With");
142   if (method->client_streaming()) {
143     printer->Print("RequestsWriter:requestWriter");
144   } else {
145     printer->Print("Request:request");
146   }
147   if (method->server_streaming()) {
148     printer->Print(" eventHandler:eventHandler] start];\n");
149   } else {
150     printer->Print(" handler:handler] start];\n");
151   }
152   printer->Print("}\n");
153 }
154
155 void PrintAdvancedImplementation(Printer* printer,
156                                  const MethodDescriptor* method,
157                                  map< ::grpc::string, ::grpc::string> vars) {
158   printer->Print("{\n");
159   printer->Print(vars, "  return [self RPCToMethod:@\"$method_name$\"\n");
160
161   printer->Print("            requestsWriter:");
162   if (method->client_streaming()) {
163     printer->Print("requestWriter\n");
164   } else {
165     printer->Print("[GRXWriter writerWithValue:request]\n");
166   }
167
168   printer->Print(vars, "             responseClass:[$response_class$ class]\n");
169
170   printer->Print("        responsesWriteable:[GRXWriteable ");
171   if (method->server_streaming()) {
172     printer->Print("writeableWithEventHandler:eventHandler]];\n");
173   } else {
174     printer->Print("writeableWithSingleHandler:handler]];\n");
175   }
176
177   printer->Print("}\n");
178 }
179
180 void PrintMethodImplementations(Printer* printer,
181                                 const MethodDescriptor* method) {
182   map< ::grpc::string, ::grpc::string> vars = GetMethodVars(method);
183
184   PrintProtoRpcDeclarationAsPragma(printer, method, vars);
185
186   // TODO(jcanizales): Print documentation from the method.
187   PrintSimpleSignature(printer, method, vars);
188   PrintSimpleImplementation(printer, method, vars);
189
190   printer->Print("// Returns a not-yet-started RPC object.\n");
191   PrintAdvancedSignature(printer, method, vars);
192   PrintAdvancedImplementation(printer, method, vars);
193 }
194
195 }  // namespace
196
197 ::grpc::string GetAllMessageClasses(const FileDescriptor* file) {
198   ::grpc::string output;
199   set< ::grpc::string> classes;
200   for (int i = 0; i < file->service_count(); i++) {
201     const auto service = file->service(i);
202     for (int i = 0; i < service->method_count(); i++) {
203       const auto method = service->method(i);
204       classes.insert(ClassName(method->input_type()));
205       classes.insert(ClassName(method->output_type()));
206     }
207   }
208   for (auto one_class : classes) {
209     output += "@class " + one_class + ";\n";
210   }
211
212   return output;
213 }
214
215 ::grpc::string GetProtocol(const ServiceDescriptor* service) {
216   ::grpc::string output;
217
218   // Scope the output stream so it closes and finalizes output to the string.
219   grpc::protobuf::io::StringOutputStream output_stream(&output);
220   Printer printer(&output_stream, '$');
221
222   map< ::grpc::string, ::grpc::string> vars = {
223       {"service_class", ServiceClassName(service)}};
224
225   printer.Print(vars, "@protocol $service_class$ <NSObject>\n\n");
226   for (int i = 0; i < service->method_count(); i++) {
227     PrintMethodDeclarations(&printer, service->method(i));
228   }
229   printer.Print("@end\n\n");
230
231   return output;
232 }
233
234 ::grpc::string GetInterface(const ServiceDescriptor* service) {
235   ::grpc::string output;
236
237   // Scope the output stream so it closes and finalizes output to the string.
238   grpc::protobuf::io::StringOutputStream output_stream(&output);
239   Printer printer(&output_stream, '$');
240
241   map< ::grpc::string, ::grpc::string> vars = {
242       {"service_class", ServiceClassName(service)}};
243
244   printer.Print(vars,
245                 "/**\n"
246                 " * Basic service implementation, over gRPC, that only does\n"
247                 " * marshalling and parsing.\n"
248                 " */\n");
249   printer.Print(vars,
250                 "@interface $service_class$ :"
251                 " GRPCProtoService<$service_class$>\n");
252   printer.Print(
253       "- (instancetype)initWithHost:(NSString *)host"
254       " NS_DESIGNATED_INITIALIZER;\n");
255   printer.Print("+ (instancetype)serviceWithHost:(NSString *)host;\n");
256   printer.Print("@end\n");
257
258   return output;
259 }
260
261 ::grpc::string GetSource(const ServiceDescriptor* service) {
262   ::grpc::string output;
263   {
264     // Scope the output stream so it closes and finalizes output to the string.
265     grpc::protobuf::io::StringOutputStream output_stream(&output);
266     Printer printer(&output_stream, '$');
267
268     map< ::grpc::string, ::grpc::string> vars = {
269         {"service_name", service->name()},
270         {"service_class", ServiceClassName(service)},
271         {"package", service->file()->package()}};
272
273     printer.Print(vars,
274                   "@implementation $service_class$\n\n"
275                   "// Designated initializer\n"
276                   "- (instancetype)initWithHost:(NSString *)host {\n"
277                   "  self = [super initWithHost:host\n"
278                   "                 packageName:@\"$package$\"\n"
279                   "                 serviceName:@\"$service_name$\"];\n"
280                   "  return self;\n"
281                   "}\n\n");
282
283     printer.Print(
284         "// Override superclass initializer to disallow different"
285         " package and service names.\n"
286         "- (instancetype)initWithHost:(NSString *)host\n"
287         "                 packageName:(NSString *)packageName\n"
288         "                 serviceName:(NSString *)serviceName {\n"
289         "  return [self initWithHost:host];\n"
290         "}\n\n");
291
292     printer.Print(
293         "#pragma mark - Class Methods\n\n"
294         "+ (instancetype)serviceWithHost:(NSString *)host {\n"
295         "  return [[self alloc] initWithHost:host];\n"
296         "}\n\n");
297
298     printer.Print("#pragma mark - Method Implementations\n\n");
299
300     for (int i = 0; i < service->method_count(); i++) {
301       PrintMethodImplementations(&printer, service->method(i));
302     }
303
304     printer.Print("@end\n");
305   }
306   return output;
307 }
308
309 }  // namespace grpc_objective_c_generator