blob: 39f68cb95651f9c801d405d883f1bc86145f39f1 [file] [log] [blame]
murgatroid99d3efd0a2015-04-07 11:40:29 -07001/*
2 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02003 * Copyright 2015 gRPC authors.
murgatroid99d3efd0a2015-04-07 11:40:29 -07004 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02005 * 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
murgatroid99d3efd0a2015-04-07 11:40:29 -07008 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02009 * http://www.apache.org/licenses/LICENSE-2.0
murgatroid99d3efd0a2015-04-07 11:40:29 -070010 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +020011 * 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.
murgatroid99d3efd0a2015-04-07 11:40:29 -070016 *
17 */
18
19#include <map>
Muxi Yan75271d72017-09-18 17:30:20 -070020#include <set>
Jorge Canizales52592fc2015-05-26 11:53:31 -070021#include <sstream>
murgatroid99d3efd0a2015-04-07 11:40:29 -070022
Jorge Canizales52592fc2015-05-26 11:53:31 -070023#include "src/compiler/config.h"
murgatroid99d3efd0a2015-04-07 11:40:29 -070024#include "src/compiler/objective_c_generator.h"
25#include "src/compiler/objective_c_generator_helpers.h"
26
Jorge Canizales52592fc2015-05-26 11:53:31 -070027#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
murgatroid99d3efd0a2015-04-07 11:40:29 -070028
Jorge Canizales52592fc2015-05-26 11:53:31 -070029using ::google::protobuf::compiler::objectivec::ClassName;
Craig Tillerbaa14a92017-11-03 09:09:36 -070030using ::grpc::protobuf::FileDescriptor;
Mehrdad Afsharid49e1002017-11-29 11:01:36 -080031using ::grpc::protobuf::FileDescriptor;
Jorge Canizales9a065d22015-04-27 00:05:01 -070032using ::grpc::protobuf::MethodDescriptor;
Jorge Canizales472f0b02015-05-12 22:56:04 -070033using ::grpc::protobuf::ServiceDescriptor;
Craig Tillerbaa14a92017-11-03 09:09:36 -070034using ::grpc::protobuf::io::Printer;
Jorge Canizales52592fc2015-05-26 11:53:31 -070035using ::std::map;
Muxi Yan75271d72017-09-18 17:30:20 -070036using ::std::set;
murgatroid99d3efd0a2015-04-07 11:40:29 -070037
Jorge Canizales472f0b02015-05-12 22:56:04 -070038namespace grpc_objective_c_generator {
39namespace {
40
Masood Malekghassemiac592452016-07-01 11:58:04 -070041void PrintProtoRpcDeclarationAsPragma(
Craig Tillerbaa14a92017-11-03 09:09:36 -070042 Printer* printer, const MethodDescriptor* method,
Masood Malekghassemiac592452016-07-01 11:58:04 -070043 map< ::grpc::string, ::grpc::string> vars) {
Jorge Canizales9a065d22015-04-27 00:05:01 -070044 vars["client_stream"] = method->client_streaming() ? "stream " : "";
45 vars["server_stream"] = method->server_streaming() ? "stream " : "";
46
47 printer->Print(vars,
Vijay Pai181ef452015-07-14 13:52:48 -070048 "#pragma mark $method_name$($client_stream$$request_type$)"
49 " returns ($server_stream$$response_type$)\n\n");
Jorge Canizales9a065d22015-04-27 00:05:01 -070050}
51
Makarand Dharmapurikarcb79b292016-06-08 15:07:54 -070052template <typename DescriptorType>
Craig Tillerbaa14a92017-11-03 09:09:36 -070053static void PrintAllComments(const DescriptorType* desc, Printer* printer) {
Makarand Dharmapurikarcb79b292016-06-08 15:07:54 -070054 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) {
Vijay Paic04f4f12017-11-27 13:08:01 -080069 printer->PrintRaw(it->c_str() + start_pos);
Makarand Dharmapurikarcb79b292016-06-08 15:07:54 -070070 }
71 printer->Print("\n");
72 }
73 printer->Print(" */\n");
74}
75
Craig Tillerbaa14a92017-11-03 09:09:36 -070076void PrintMethodSignature(Printer* printer, const MethodDescriptor* method,
77 const map< ::grpc::string, ::grpc::string>& vars) {
Makarand Dharmapurikarcb79b292016-06-08 15:07:54 -070078 // Print comment
79 PrintAllComments(method, printer);
Jorge Canizales9a065d22015-04-27 00:05:01 -070080
81 printer->Print(vars, "- ($return_type$)$method_name$With");
82 if (method->client_streaming()) {
Jorge Canizales739c9982015-07-16 22:07:54 -070083 printer->Print("RequestsWriter:(GRXWriter *)requestWriter");
murgatroid99d3efd0a2015-04-07 11:40:29 -070084 } else {
Jorge Canizales52592fc2015-05-26 11:53:31 -070085 printer->Print(vars, "Request:($request_class$ *)request");
murgatroid99d3efd0a2015-04-07 11:40:29 -070086 }
Jorge Canizales9a065d22015-04-27 00:05:01 -070087
88 // TODO(jcanizales): Put this on a new line and align colons.
Jorge Canizales9a065d22015-04-27 00:05:01 -070089 if (method->server_streaming()) {
Vijay Pai181ef452015-07-14 13:52:48 -070090 printer->Print(vars,
91 " eventHandler:(void(^)(BOOL done, "
Masood Malekghassemiac592452016-07-01 11:58:04 -070092 "$response_class$ *_Nullable response, NSError *_Nullable "
93 "error))eventHandler");
murgatroid9925a26612015-06-25 11:22:23 -070094 } else {
Vijay Pai181ef452015-07-14 13:52:48 -070095 printer->Print(vars,
Benjamin Herzog208795c2016-04-18 18:10:14 +020096 " handler:(void(^)($response_class$ *_Nullable response, "
97 "NSError *_Nullable error))handler");
Jorge Canizales9a065d22015-04-27 00:05:01 -070098 }
murgatroid99d3efd0a2015-04-07 11:40:29 -070099}
100
Craig Tillerbaa14a92017-11-03 09:09:36 -0700101void PrintSimpleSignature(Printer* printer, const MethodDescriptor* method,
Jorge Canizales637c3652015-08-13 19:04:22 -0700102 map< ::grpc::string, ::grpc::string> vars) {
Jorge Canizales9a065d22015-04-27 00:05:01 -0700103 vars["method_name"] =
104 grpc_generator::LowercaseFirstLetter(vars["method_name"]);
105 vars["return_type"] = "void";
106 PrintMethodSignature(printer, method, vars);
murgatroid99d3efd0a2015-04-07 11:40:29 -0700107}
108
Craig Tillerbaa14a92017-11-03 09:09:36 -0700109void PrintAdvancedSignature(Printer* printer, const MethodDescriptor* method,
Jorge Canizales637c3652015-08-13 19:04:22 -0700110 map< ::grpc::string, ::grpc::string> vars) {
Jorge Canizales9a065d22015-04-27 00:05:01 -0700111 vars["method_name"] = "RPCTo" + vars["method_name"];
Makarand Dharmapurikar4f11ab12016-06-08 10:40:00 -0700112 vars["return_type"] = "GRPCProtoCall *";
Jorge Canizales9a065d22015-04-27 00:05:01 -0700113 PrintMethodSignature(printer, method, vars);
murgatroid99d3efd0a2015-04-07 11:40:29 -0700114}
115
Masood Malekghassemiac592452016-07-01 11:58:04 -0700116inline map< ::grpc::string, ::grpc::string> GetMethodVars(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700117 const MethodDescriptor* method) {
Jorge Canizales637c3652015-08-13 19:04:22 -0700118 map< ::grpc::string, ::grpc::string> res;
vjpaic7eed742015-07-14 10:47:28 -0700119 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());
Vijay Pai181ef452015-07-14 13:52:48 -0700124 return res;
Jorge Canizales52592fc2015-05-26 11:53:31 -0700125}
126
Craig Tillerbaa14a92017-11-03 09:09:36 -0700127void PrintMethodDeclarations(Printer* printer, const MethodDescriptor* method) {
Jorge Canizales637c3652015-08-13 19:04:22 -0700128 map< ::grpc::string, ::grpc::string> vars = GetMethodVars(method);
murgatroid99ac0002a2015-04-07 12:49:14 -0700129
Jorge Canizales9a065d22015-04-27 00:05:01 -0700130 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
Craig Tillerbaa14a92017-11-03 09:09:36 -0700138void PrintSimpleImplementation(Printer* printer, const MethodDescriptor* method,
Jorge Canizales637c3652015-08-13 19:04:22 -0700139 map< ::grpc::string, ::grpc::string> vars) {
Jorge Canizales472f0b02015-05-12 22:56:04 -0700140 printer->Print("{\n");
Jorge Canizales1900dfc2015-05-15 09:44:04 -0700141 printer->Print(vars, " [[self RPCTo$method_name$With");
Jorge Canizales472f0b02015-05-12 22:56:04 -0700142 if (method->client_streaming()) {
murgatroid9925a26612015-06-25 11:22:23 -0700143 printer->Print("RequestsWriter:requestWriter");
Jorge Canizales472f0b02015-05-12 22:56:04 -0700144 } else {
145 printer->Print("Request:request");
146 }
murgatroid9925a26612015-06-25 11:22:23 -0700147 if (method->server_streaming()) {
148 printer->Print(" eventHandler:eventHandler] start];\n");
149 } else {
150 printer->Print(" handler:handler] start];\n");
151 }
Jorge Canizales472f0b02015-05-12 22:56:04 -0700152 printer->Print("}\n");
153}
154
Craig Tillerbaa14a92017-11-03 09:09:36 -0700155void PrintAdvancedImplementation(Printer* printer,
156 const MethodDescriptor* method,
Jorge Canizales637c3652015-08-13 19:04:22 -0700157 map< ::grpc::string, ::grpc::string> vars) {
Jorge Canizales472f0b02015-05-12 22:56:04 -0700158 printer->Print("{\n");
159 printer->Print(vars, " return [self RPCToMethod:@\"$method_name$\"\n");
160
161 printer->Print(" requestsWriter:");
162 if (method->client_streaming()) {
murgatroid9925a26612015-06-25 11:22:23 -0700163 printer->Print("requestWriter\n");
Jorge Canizales472f0b02015-05-12 22:56:04 -0700164 } else {
165 printer->Print("[GRXWriter writerWithValue:request]\n");
166 }
167
Jorge Canizales52592fc2015-05-26 11:53:31 -0700168 printer->Print(vars, " responseClass:[$response_class$ class]\n");
Jorge Canizales472f0b02015-05-12 22:56:04 -0700169
170 printer->Print(" responsesWriteable:[GRXWriteable ");
171 if (method->server_streaming()) {
Jorge Canizalesf95ddba2015-08-12 10:51:56 -0700172 printer->Print("writeableWithEventHandler:eventHandler]];\n");
Jorge Canizales472f0b02015-05-12 22:56:04 -0700173 } else {
Jorge Canizalesf95ddba2015-08-12 10:51:56 -0700174 printer->Print("writeableWithSingleHandler:handler]];\n");
Jorge Canizales472f0b02015-05-12 22:56:04 -0700175 }
176
177 printer->Print("}\n");
178}
179
Craig Tillerbaa14a92017-11-03 09:09:36 -0700180void PrintMethodImplementations(Printer* printer,
181 const MethodDescriptor* method) {
Jorge Canizales637c3652015-08-13 19:04:22 -0700182 map< ::grpc::string, ::grpc::string> vars = GetMethodVars(method);
murgatroid99ac0002a2015-04-07 12:49:14 -0700183
Jorge Canizales472f0b02015-05-12 22:56:04 -0700184 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");
murgatroid99ac0002a2015-04-07 12:49:14 -0700191 PrintAdvancedSignature(printer, method, vars);
Jorge Canizales472f0b02015-05-12 22:56:04 -0700192 PrintAdvancedImplementation(printer, method, vars);
murgatroid99ac0002a2015-04-07 12:49:14 -0700193}
194
Vijay Pai181ef452015-07-14 13:52:48 -0700195} // namespace
murgatroid99ac0002a2015-04-07 12:49:14 -0700196
Craig Tillerbaa14a92017-11-03 09:09:36 -0700197::grpc::string GetAllMessageClasses(const FileDescriptor* file) {
Muxi Yan75271d72017-09-18 17:30:20 -0700198 ::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) {
Muxi Yan19ca19b2018-04-04 11:15:26 -0700209 output += "@class " + one_class + ";\n";
Muxi Yan75271d72017-09-18 17:30:20 -0700210 }
211
212 return output;
213}
214
Tyson Roberts87c40012018-02-22 11:34:53 +0900215::grpc::string GetProtocol(const ServiceDescriptor* service) {
Jorge Canizalesb015dfb2015-08-13 18:41:29 -0700216 ::grpc::string output;
Vijay Pai181ef452015-07-14 13:52:48 -0700217
Tyson Roberts87c40012018-02-22 11:34:53 +0900218 // 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, '$');
Jorge Canizales52592fc2015-05-26 11:53:31 -0700221
Tyson Roberts87c40012018-02-22 11:34:53 +0900222 map< ::grpc::string, ::grpc::string> vars = {
223 {"service_class", ServiceClassName(service)}};
Jorge Canizales9a065d22015-04-27 00:05:01 -0700224
Juanli Shen10a8c162018-05-07 20:25:44 -0700225 printer.Print(vars, "@protocol $service_class$ <NSObject>\n\n");
Tyson Roberts87c40012018-02-22 11:34:53 +0900226 for (int i = 0; i < service->method_count(); i++) {
227 PrintMethodDeclarations(&printer, service->method(i));
murgatroid99d3efd0a2015-04-07 11:40:29 -0700228 }
Tyson Roberts87c40012018-02-22 11:34:53 +0900229 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$ :"
Muxi Yandcb05c12018-05-03 10:16:34 -0700251 " GRPCProtoService<$service_class$>\n");
Muxi Yan3d35c542018-02-27 10:10:46 -0800252 printer.Print(
253 "- (instancetype)initWithHost:(NSString *)host"
254 " NS_DESIGNATED_INITIALIZER;\n");
Tyson Roberts87c40012018-02-22 11:34:53 +0900255 printer.Print("+ (instancetype)serviceWithHost:(NSString *)host;\n");
256 printer.Print("@end\n");
257
murgatroid99d3efd0a2015-04-07 11:40:29 -0700258 return output;
259}
260
Craig Tillerbaa14a92017-11-03 09:09:36 -0700261::grpc::string GetSource(const ServiceDescriptor* service) {
Masood Malekghassemiac592452016-07-01 11:58:04 -0700262 ::grpc::string output;
Jan Tattermusch5dcebd92015-05-27 15:30:59 -0700263 {
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, '$');
Jorge Canizales9a065d22015-04-27 00:05:01 -0700267
Masood Malekghassemiac592452016-07-01 11:58:04 -0700268 map< ::grpc::string, ::grpc::string> vars = {
269 {"service_name", service->name()},
270 {"service_class", ServiceClassName(service)},
271 {"package", service->file()->package()}};
Jorge Canizales472f0b02015-05-12 22:56:04 -0700272
Tyson Roberts87c40012018-02-22 11:34:53 +0900273 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");
Vijay Pai181ef452015-07-14 13:52:48 -0700282
Muxi Yan3d35c542018-02-27 10:10:46 -0800283 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");
Tyson Roberts87c40012018-02-22 11:34:53 +0900291
Muxi Yan3d35c542018-02-27 10:10:46 -0800292 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");
Tyson Roberts87c40012018-02-22 11:34:53 +0900297
298 printer.Print("#pragma mark - Method Implementations\n\n");
Jorge Canizales472f0b02015-05-12 22:56:04 -0700299
Jan Tattermusch5dcebd92015-05-27 15:30:59 -0700300 for (int i = 0; i < service->method_count(); i++) {
Jorge Canizales52592fc2015-05-26 11:53:31 -0700301 PrintMethodImplementations(&printer, service->method(i));
Jan Tattermusch5dcebd92015-05-27 15:30:59 -0700302 }
Jorge Canizales472f0b02015-05-12 22:56:04 -0700303
Jan Tattermusch5dcebd92015-05-27 15:30:59 -0700304 printer.Print("@end\n");
murgatroid99d3efd0a2015-04-07 11:40:29 -0700305 }
murgatroid99d3efd0a2015-04-07 11:40:29 -0700306 return output;
307}
308
Vijay Pai181ef452015-07-14 13:52:48 -0700309} // namespace grpc_objective_c_generator