blob: 8fe30e97e94f0b57843832f430150f206ca103f1 [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;
Jorge Canizales9a065d22015-04-27 00:05:01 -070031using ::grpc::protobuf::MethodDescriptor;
Jorge Canizales472f0b02015-05-12 22:56:04 -070032using ::grpc::protobuf::ServiceDescriptor;
Craig Tillerbaa14a92017-11-03 09:09:36 -070033using ::grpc::protobuf::io::Printer;
Jorge Canizales52592fc2015-05-26 11:53:31 -070034using ::std::map;
Muxi Yan75271d72017-09-18 17:30:20 -070035using ::std::set;
murgatroid99d3efd0a2015-04-07 11:40:29 -070036
Jorge Canizales472f0b02015-05-12 22:56:04 -070037namespace grpc_objective_c_generator {
38namespace {
39
Masood Malekghassemiac592452016-07-01 11:58:04 -070040void PrintProtoRpcDeclarationAsPragma(
Craig Tillerbaa14a92017-11-03 09:09:36 -070041 Printer* printer, const MethodDescriptor* method,
Masood Malekghassemiac592452016-07-01 11:58:04 -070042 map< ::grpc::string, ::grpc::string> vars) {
Jorge Canizales9a065d22015-04-27 00:05:01 -070043 vars["client_stream"] = method->client_streaming() ? "stream " : "";
44 vars["server_stream"] = method->server_streaming() ? "stream " : "";
45
46 printer->Print(vars,
Vijay Pai181ef452015-07-14 13:52:48 -070047 "#pragma mark $method_name$($client_stream$$request_type$)"
48 " returns ($server_stream$$response_type$)\n\n");
Jorge Canizales9a065d22015-04-27 00:05:01 -070049}
50
Makarand Dharmapurikarcb79b292016-06-08 15:07:54 -070051template <typename DescriptorType>
Craig Tillerbaa14a92017-11-03 09:09:36 -070052static void PrintAllComments(const DescriptorType* desc, Printer* printer) {
Makarand Dharmapurikarcb79b292016-06-08 15:07:54 -070053 std::vector<grpc::string> comments;
54 grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_LEADING_DETACHED,
55 &comments);
56 grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_LEADING,
57 &comments);
58 grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_TRAILING,
59 &comments);
60 if (comments.empty()) {
61 return;
62 }
63 printer->Print("/**\n");
64 for (auto it = comments.begin(); it != comments.end(); ++it) {
65 printer->Print(" * ");
66 size_t start_pos = it->find_first_not_of(' ');
67 if (start_pos != grpc::string::npos) {
Vijay Paic04f4f12017-11-27 13:08:01 -080068 printer->PrintRaw(it->c_str() + start_pos);
Makarand Dharmapurikarcb79b292016-06-08 15:07:54 -070069 }
70 printer->Print("\n");
71 }
72 printer->Print(" */\n");
73}
74
Craig Tillerbaa14a92017-11-03 09:09:36 -070075void PrintMethodSignature(Printer* printer, const MethodDescriptor* method,
76 const map< ::grpc::string, ::grpc::string>& vars) {
Makarand Dharmapurikarcb79b292016-06-08 15:07:54 -070077 // Print comment
78 PrintAllComments(method, printer);
Jorge Canizales9a065d22015-04-27 00:05:01 -070079
80 printer->Print(vars, "- ($return_type$)$method_name$With");
81 if (method->client_streaming()) {
Jorge Canizales739c9982015-07-16 22:07:54 -070082 printer->Print("RequestsWriter:(GRXWriter *)requestWriter");
murgatroid99d3efd0a2015-04-07 11:40:29 -070083 } else {
Jorge Canizales52592fc2015-05-26 11:53:31 -070084 printer->Print(vars, "Request:($request_class$ *)request");
murgatroid99d3efd0a2015-04-07 11:40:29 -070085 }
Jorge Canizales9a065d22015-04-27 00:05:01 -070086
87 // TODO(jcanizales): Put this on a new line and align colons.
Jorge Canizales9a065d22015-04-27 00:05:01 -070088 if (method->server_streaming()) {
Vijay Pai181ef452015-07-14 13:52:48 -070089 printer->Print(vars,
90 " eventHandler:(void(^)(BOOL done, "
Masood Malekghassemiac592452016-07-01 11:58:04 -070091 "$response_class$ *_Nullable response, NSError *_Nullable "
92 "error))eventHandler");
murgatroid9925a26612015-06-25 11:22:23 -070093 } else {
Vijay Pai181ef452015-07-14 13:52:48 -070094 printer->Print(vars,
Benjamin Herzog208795c2016-04-18 18:10:14 +020095 " handler:(void(^)($response_class$ *_Nullable response, "
96 "NSError *_Nullable error))handler");
Jorge Canizales9a065d22015-04-27 00:05:01 -070097 }
murgatroid99d3efd0a2015-04-07 11:40:29 -070098}
99
Craig Tillerbaa14a92017-11-03 09:09:36 -0700100void PrintSimpleSignature(Printer* printer, const MethodDescriptor* method,
Jorge Canizales637c3652015-08-13 19:04:22 -0700101 map< ::grpc::string, ::grpc::string> vars) {
Jorge Canizales9a065d22015-04-27 00:05:01 -0700102 vars["method_name"] =
103 grpc_generator::LowercaseFirstLetter(vars["method_name"]);
104 vars["return_type"] = "void";
105 PrintMethodSignature(printer, method, vars);
murgatroid99d3efd0a2015-04-07 11:40:29 -0700106}
107
Craig Tillerbaa14a92017-11-03 09:09:36 -0700108void PrintAdvancedSignature(Printer* printer, const MethodDescriptor* method,
Jorge Canizales637c3652015-08-13 19:04:22 -0700109 map< ::grpc::string, ::grpc::string> vars) {
Jorge Canizales9a065d22015-04-27 00:05:01 -0700110 vars["method_name"] = "RPCTo" + vars["method_name"];
Makarand Dharmapurikar4f11ab12016-06-08 10:40:00 -0700111 vars["return_type"] = "GRPCProtoCall *";
Jorge Canizales9a065d22015-04-27 00:05:01 -0700112 PrintMethodSignature(printer, method, vars);
murgatroid99d3efd0a2015-04-07 11:40:29 -0700113}
114
Masood Malekghassemiac592452016-07-01 11:58:04 -0700115inline map< ::grpc::string, ::grpc::string> GetMethodVars(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700116 const MethodDescriptor* method) {
Jorge Canizales637c3652015-08-13 19:04:22 -0700117 map< ::grpc::string, ::grpc::string> res;
vjpaic7eed742015-07-14 10:47:28 -0700118 res["method_name"] = method->name();
119 res["request_type"] = method->input_type()->name();
120 res["response_type"] = method->output_type()->name();
121 res["request_class"] = ClassName(method->input_type());
122 res["response_class"] = ClassName(method->output_type());
Vijay Pai181ef452015-07-14 13:52:48 -0700123 return res;
Jorge Canizales52592fc2015-05-26 11:53:31 -0700124}
125
Craig Tillerbaa14a92017-11-03 09:09:36 -0700126void PrintMethodDeclarations(Printer* printer, const MethodDescriptor* method) {
Jorge Canizales637c3652015-08-13 19:04:22 -0700127 map< ::grpc::string, ::grpc::string> vars = GetMethodVars(method);
murgatroid99ac0002a2015-04-07 12:49:14 -0700128
Jorge Canizales9a065d22015-04-27 00:05:01 -0700129 PrintProtoRpcDeclarationAsPragma(printer, method, vars);
130
131 PrintSimpleSignature(printer, method, vars);
132 printer->Print(";\n\n");
133 PrintAdvancedSignature(printer, method, vars);
134 printer->Print(";\n\n\n");
135}
136
Craig Tillerbaa14a92017-11-03 09:09:36 -0700137void PrintSimpleImplementation(Printer* printer, const MethodDescriptor* method,
Jorge Canizales637c3652015-08-13 19:04:22 -0700138 map< ::grpc::string, ::grpc::string> vars) {
Jorge Canizales472f0b02015-05-12 22:56:04 -0700139 printer->Print("{\n");
Jorge Canizales1900dfc2015-05-15 09:44:04 -0700140 printer->Print(vars, " [[self RPCTo$method_name$With");
Jorge Canizales472f0b02015-05-12 22:56:04 -0700141 if (method->client_streaming()) {
murgatroid9925a26612015-06-25 11:22:23 -0700142 printer->Print("RequestsWriter:requestWriter");
Jorge Canizales472f0b02015-05-12 22:56:04 -0700143 } else {
144 printer->Print("Request:request");
145 }
murgatroid9925a26612015-06-25 11:22:23 -0700146 if (method->server_streaming()) {
147 printer->Print(" eventHandler:eventHandler] start];\n");
148 } else {
149 printer->Print(" handler:handler] start];\n");
150 }
Jorge Canizales472f0b02015-05-12 22:56:04 -0700151 printer->Print("}\n");
152}
153
Craig Tillerbaa14a92017-11-03 09:09:36 -0700154void PrintAdvancedImplementation(Printer* printer,
155 const MethodDescriptor* method,
Jorge Canizales637c3652015-08-13 19:04:22 -0700156 map< ::grpc::string, ::grpc::string> vars) {
Jorge Canizales472f0b02015-05-12 22:56:04 -0700157 printer->Print("{\n");
158 printer->Print(vars, " return [self RPCToMethod:@\"$method_name$\"\n");
159
160 printer->Print(" requestsWriter:");
161 if (method->client_streaming()) {
murgatroid9925a26612015-06-25 11:22:23 -0700162 printer->Print("requestWriter\n");
Jorge Canizales472f0b02015-05-12 22:56:04 -0700163 } else {
164 printer->Print("[GRXWriter writerWithValue:request]\n");
165 }
166
Jorge Canizales52592fc2015-05-26 11:53:31 -0700167 printer->Print(vars, " responseClass:[$response_class$ class]\n");
Jorge Canizales472f0b02015-05-12 22:56:04 -0700168
169 printer->Print(" responsesWriteable:[GRXWriteable ");
170 if (method->server_streaming()) {
Jorge Canizalesf95ddba2015-08-12 10:51:56 -0700171 printer->Print("writeableWithEventHandler:eventHandler]];\n");
Jorge Canizales472f0b02015-05-12 22:56:04 -0700172 } else {
Jorge Canizalesf95ddba2015-08-12 10:51:56 -0700173 printer->Print("writeableWithSingleHandler:handler]];\n");
Jorge Canizales472f0b02015-05-12 22:56:04 -0700174 }
175
176 printer->Print("}\n");
177}
178
Craig Tillerbaa14a92017-11-03 09:09:36 -0700179void PrintMethodImplementations(Printer* printer,
180 const MethodDescriptor* method) {
Jorge Canizales637c3652015-08-13 19:04:22 -0700181 map< ::grpc::string, ::grpc::string> vars = GetMethodVars(method);
murgatroid99ac0002a2015-04-07 12:49:14 -0700182
Jorge Canizales472f0b02015-05-12 22:56:04 -0700183 PrintProtoRpcDeclarationAsPragma(printer, method, vars);
184
185 // TODO(jcanizales): Print documentation from the method.
186 PrintSimpleSignature(printer, method, vars);
187 PrintSimpleImplementation(printer, method, vars);
188
189 printer->Print("// Returns a not-yet-started RPC object.\n");
murgatroid99ac0002a2015-04-07 12:49:14 -0700190 PrintAdvancedSignature(printer, method, vars);
Jorge Canizales472f0b02015-05-12 22:56:04 -0700191 PrintAdvancedImplementation(printer, method, vars);
murgatroid99ac0002a2015-04-07 12:49:14 -0700192}
193
Vijay Pai181ef452015-07-14 13:52:48 -0700194} // namespace
murgatroid99ac0002a2015-04-07 12:49:14 -0700195
Craig Tillerbaa14a92017-11-03 09:09:36 -0700196::grpc::string GetAllMessageClasses(const FileDescriptor* file) {
Muxi Yan75271d72017-09-18 17:30:20 -0700197 ::grpc::string output;
198 set< ::grpc::string> classes;
199 for (int i = 0; i < file->service_count(); i++) {
200 const auto service = file->service(i);
201 for (int i = 0; i < service->method_count(); i++) {
202 const auto method = service->method(i);
203 classes.insert(ClassName(method->input_type()));
204 classes.insert(ClassName(method->output_type()));
205 }
206 }
207 for (auto one_class : classes) {
208 output += " @class " + one_class + ";\n";
209 }
210
211 return output;
212}
213
Craig Tillerbaa14a92017-11-03 09:09:36 -0700214::grpc::string GetHeader(const ServiceDescriptor* service) {
Jorge Canizalesb015dfb2015-08-13 18:41:29 -0700215 ::grpc::string output;
Jan Tattermusch5dcebd92015-05-27 15:30:59 -0700216 {
217 // Scope the output stream so it closes and finalizes output to the string.
218 grpc::protobuf::io::StringOutputStream output_stream(&output);
219 Printer printer(&output_stream, '$');
Vijay Pai181ef452015-07-14 13:52:48 -0700220
Masood Malekghassemiac592452016-07-01 11:58:04 -0700221 map< ::grpc::string, ::grpc::string> vars = {
222 {"service_class", ServiceClassName(service)}};
Jorge Canizales52592fc2015-05-26 11:53:31 -0700223
224 printer.Print(vars, "@protocol $service_class$ <NSObject>\n\n");
Jorge Canizales9a065d22015-04-27 00:05:01 -0700225
Jan Tattermusch5dcebd92015-05-27 15:30:59 -0700226 for (int i = 0; i < service->method_count(); i++) {
Jorge Canizales52592fc2015-05-26 11:53:31 -0700227 PrintMethodDeclarations(&printer, service->method(i));
Jan Tattermusch5dcebd92015-05-27 15:30:59 -0700228 }
229 printer.Print("@end\n\n");
230
Vijay Pai181ef452015-07-14 13:52:48 -0700231 printer.Print(
Makarand Dharmapurikarcb79b292016-06-08 15:07:54 -0700232 "/**\n"
233 " * Basic service implementation, over gRPC, that only does\n"
234 " * marshalling and parsing.\n"
235 " */\n");
Vijay Pai181ef452015-07-14 13:52:48 -0700236 printer.Print(vars,
237 "@interface $service_class$ :"
Makarand Dharmapurikar6f950102016-06-07 16:52:19 -0700238 " GRPCProtoService<$service_class$>\n");
Vijay Pai181ef452015-07-14 13:52:48 -0700239 printer.Print(
240 "- (instancetype)initWithHost:(NSString *)host"
241 " NS_DESIGNATED_INITIALIZER;\n");
Nate Kibler6d197242015-09-25 10:02:20 -0700242 printer.Print("+ (instancetype)serviceWithHost:(NSString *)host;\n");
Jan Tattermusch5dcebd92015-05-27 15:30:59 -0700243 printer.Print("@end\n");
murgatroid99d3efd0a2015-04-07 11:40:29 -0700244 }
murgatroid99d3efd0a2015-04-07 11:40:29 -0700245 return output;
246}
247
Craig Tillerbaa14a92017-11-03 09:09:36 -0700248::grpc::string GetSource(const ServiceDescriptor* service) {
Masood Malekghassemiac592452016-07-01 11:58:04 -0700249 ::grpc::string output;
Jan Tattermusch5dcebd92015-05-27 15:30:59 -0700250 {
251 // Scope the output stream so it closes and finalizes output to the string.
252 grpc::protobuf::io::StringOutputStream output_stream(&output);
253 Printer printer(&output_stream, '$');
Jorge Canizales9a065d22015-04-27 00:05:01 -0700254
Masood Malekghassemiac592452016-07-01 11:58:04 -0700255 map< ::grpc::string, ::grpc::string> vars = {
256 {"service_name", service->name()},
257 {"service_class", ServiceClassName(service)},
258 {"package", service->file()->package()}};
Jorge Canizales472f0b02015-05-12 22:56:04 -0700259
Jorge Canizales52592fc2015-05-26 11:53:31 -0700260 printer.Print(vars, "@implementation $service_class$\n\n");
Vijay Pai181ef452015-07-14 13:52:48 -0700261
Jan Tattermusch5dcebd92015-05-27 15:30:59 -0700262 printer.Print("// Designated initializer\n");
263 printer.Print("- (instancetype)initWithHost:(NSString *)host {\n");
Masood Malekghassemiac592452016-07-01 11:58:04 -0700264 printer.Print(
265 vars,
Vijay Pai181ef452015-07-14 13:52:48 -0700266 " return (self = [super initWithHost:host"
Makarand Dharmapurikar857495a2016-06-09 14:25:31 -0700267 " packageName:@\"$package$\" serviceName:@\"$service_name$\"]);\n");
Jan Tattermusch5dcebd92015-05-27 15:30:59 -0700268 printer.Print("}\n\n");
Vijay Pai181ef452015-07-14 13:52:48 -0700269 printer.Print(
270 "// Override superclass initializer to disallow different"
Jan Tattermusch5dcebd92015-05-27 15:30:59 -0700271 " package and service names.\n");
272 printer.Print("- (instancetype)initWithHost:(NSString *)host\n");
273 printer.Print(" packageName:(NSString *)packageName\n");
274 printer.Print(" serviceName:(NSString *)serviceName {\n");
275 printer.Print(" return [self initWithHost:host];\n");
Nate Kibler6d197242015-09-25 10:02:20 -0700276 printer.Print("}\n\n");
Nate Kibler6d197242015-09-25 10:02:20 -0700277 printer.Print("+ (instancetype)serviceWithHost:(NSString *)host {\n");
278 printer.Print(" return [[self alloc] initWithHost:host];\n");
Jan Tattermusch5dcebd92015-05-27 15:30:59 -0700279 printer.Print("}\n\n\n");
Jorge Canizales472f0b02015-05-12 22:56:04 -0700280
Jan Tattermusch5dcebd92015-05-27 15:30:59 -0700281 for (int i = 0; i < service->method_count(); i++) {
Jorge Canizales52592fc2015-05-26 11:53:31 -0700282 PrintMethodImplementations(&printer, service->method(i));
Jan Tattermusch5dcebd92015-05-27 15:30:59 -0700283 }
Jorge Canizales472f0b02015-05-12 22:56:04 -0700284
Jan Tattermusch5dcebd92015-05-27 15:30:59 -0700285 printer.Print("@end\n");
murgatroid99d3efd0a2015-04-07 11:40:29 -0700286 }
murgatroid99d3efd0a2015-04-07 11:40:29 -0700287 return output;
288}
289
Vijay Pai181ef452015-07-14 13:52:48 -0700290} // namespace grpc_objective_c_generator