objective_c_generator.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /*
  2. *
  3. * Copyright 2015, Google Inc.
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are
  8. * met:
  9. *
  10. * * Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * * Redistributions in binary form must reproduce the above
  13. * copyright notice, this list of conditions and the following disclaimer
  14. * in the documentation and/or other materials provided with the
  15. * distribution.
  16. * * Neither the name of Google Inc. nor the names of its
  17. * contributors may be used to endorse or promote products derived from
  18. * this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. *
  32. */
  33. #include <map>
  34. #include <sstream>
  35. #include "src/compiler/config.h"
  36. #include "src/compiler/objective_c_generator.h"
  37. #include "src/compiler/objective_c_generator_helpers.h"
  38. #include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
  39. using ::google::protobuf::compiler::objectivec::ClassName;
  40. using ::grpc::protobuf::io::Printer;
  41. using ::grpc::protobuf::MethodDescriptor;
  42. using ::grpc::protobuf::ServiceDescriptor;
  43. using ::std::map;
  44. namespace grpc_objective_c_generator {
  45. namespace {
  46. void PrintProtoRpcDeclarationAsPragma(
  47. Printer *printer, const MethodDescriptor *method,
  48. map< ::grpc::string, ::grpc::string> vars) {
  49. vars["client_stream"] = method->client_streaming() ? "stream " : "";
  50. vars["server_stream"] = method->server_streaming() ? "stream " : "";
  51. printer->Print(vars,
  52. "#pragma mark $method_name$($client_stream$$request_type$)"
  53. " returns ($server_stream$$response_type$)\n\n");
  54. }
  55. template <typename DescriptorType>
  56. static void PrintAllComments(const DescriptorType *desc, Printer *printer) {
  57. std::vector<grpc::string> comments;
  58. grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_LEADING_DETACHED,
  59. &comments);
  60. grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_LEADING,
  61. &comments);
  62. grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_TRAILING,
  63. &comments);
  64. if (comments.empty()) {
  65. return;
  66. }
  67. printer->Print("/**\n");
  68. for (auto it = comments.begin(); it != comments.end(); ++it) {
  69. printer->Print(" * ");
  70. size_t start_pos = it->find_first_not_of(' ');
  71. if (start_pos != grpc::string::npos) {
  72. printer->Print(it->c_str() + start_pos);
  73. }
  74. printer->Print("\n");
  75. }
  76. printer->Print(" */\n");
  77. }
  78. void PrintMethodSignature(Printer *printer, const MethodDescriptor *method,
  79. const map< ::grpc::string, ::grpc::string> &vars) {
  80. // Print comment
  81. PrintAllComments(method, printer);
  82. printer->Print(vars, "- ($return_type$)$method_name$With");
  83. if (method->client_streaming()) {
  84. printer->Print("RequestsWriter:(GRXWriter *)requestWriter");
  85. } else {
  86. printer->Print(vars, "Request:($request_class$ *)request");
  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. void PrintSimpleSignature(Printer *printer, const MethodDescriptor *method,
  101. map< ::grpc::string, ::grpc::string> vars) {
  102. vars["method_name"] =
  103. grpc_generator::LowercaseFirstLetter(vars["method_name"]);
  104. vars["return_type"] = "void";
  105. PrintMethodSignature(printer, method, vars);
  106. }
  107. void PrintAdvancedSignature(Printer *printer, const MethodDescriptor *method,
  108. map< ::grpc::string, ::grpc::string> vars) {
  109. vars["method_name"] = "RPCTo" + vars["method_name"];
  110. vars["return_type"] = "GRPCProtoCall *";
  111. PrintMethodSignature(printer, method, vars);
  112. }
  113. inline map< ::grpc::string, ::grpc::string> GetMethodVars(
  114. const MethodDescriptor *method) {
  115. map< ::grpc::string, ::grpc::string> res;
  116. res["method_name"] = method->name();
  117. res["request_type"] = method->input_type()->name();
  118. res["response_type"] = method->output_type()->name();
  119. res["request_class"] = ClassName(method->input_type());
  120. res["response_class"] = ClassName(method->output_type());
  121. return res;
  122. }
  123. void PrintMethodDeclarations(Printer *printer, const MethodDescriptor *method) {
  124. map< ::grpc::string, ::grpc::string> vars = GetMethodVars(method);
  125. PrintProtoRpcDeclarationAsPragma(printer, method, vars);
  126. PrintSimpleSignature(printer, method, vars);
  127. printer->Print(";\n\n");
  128. PrintAdvancedSignature(printer, method, vars);
  129. printer->Print(";\n\n\n");
  130. }
  131. void PrintSimpleImplementation(Printer *printer, const MethodDescriptor *method,
  132. map< ::grpc::string, ::grpc::string> vars) {
  133. printer->Print("{\n");
  134. printer->Print(vars, " [[self RPCTo$method_name$With");
  135. if (method->client_streaming()) {
  136. printer->Print("RequestsWriter:requestWriter");
  137. } else {
  138. printer->Print("Request:request");
  139. }
  140. if (method->server_streaming()) {
  141. printer->Print(" eventHandler:eventHandler] start];\n");
  142. } else {
  143. printer->Print(" handler:handler] start];\n");
  144. }
  145. printer->Print("}\n");
  146. }
  147. void PrintAdvancedImplementation(Printer *printer,
  148. const MethodDescriptor *method,
  149. map< ::grpc::string, ::grpc::string> vars) {
  150. printer->Print("{\n");
  151. printer->Print(vars, " return [self RPCToMethod:@\"$method_name$\"\n");
  152. printer->Print(" requestsWriter:");
  153. if (method->client_streaming()) {
  154. printer->Print("requestWriter\n");
  155. } else {
  156. printer->Print("[GRXWriter writerWithValue:request]\n");
  157. }
  158. printer->Print(vars, " responseClass:[$response_class$ class]\n");
  159. printer->Print(" responsesWriteable:[GRXWriteable ");
  160. if (method->server_streaming()) {
  161. printer->Print("writeableWithEventHandler:eventHandler]];\n");
  162. } else {
  163. printer->Print("writeableWithSingleHandler:handler]];\n");
  164. }
  165. printer->Print("}\n");
  166. }
  167. void PrintMethodImplementations(Printer *printer,
  168. const MethodDescriptor *method) {
  169. map< ::grpc::string, ::grpc::string> vars = GetMethodVars(method);
  170. PrintProtoRpcDeclarationAsPragma(printer, method, vars);
  171. // TODO(jcanizales): Print documentation from the method.
  172. PrintSimpleSignature(printer, method, vars);
  173. PrintSimpleImplementation(printer, method, vars);
  174. printer->Print("// Returns a not-yet-started RPC object.\n");
  175. PrintAdvancedSignature(printer, method, vars);
  176. PrintAdvancedImplementation(printer, method, vars);
  177. }
  178. } // namespace
  179. ::grpc::string GetHeader(const ServiceDescriptor *service) {
  180. ::grpc::string output;
  181. {
  182. // Scope the output stream so it closes and finalizes output to the string.
  183. grpc::protobuf::io::StringOutputStream output_stream(&output);
  184. Printer printer(&output_stream, '$');
  185. map< ::grpc::string, ::grpc::string> vars = {
  186. {"service_class", ServiceClassName(service)}};
  187. printer.Print(vars, "@protocol $service_class$ <NSObject>\n\n");
  188. for (int i = 0; i < service->method_count(); i++) {
  189. PrintMethodDeclarations(&printer, service->method(i));
  190. }
  191. printer.Print("@end\n\n");
  192. printer.Print(
  193. "/**\n"
  194. " * Basic service implementation, over gRPC, that only does\n"
  195. " * marshalling and parsing.\n"
  196. " */\n");
  197. printer.Print(vars,
  198. "@interface $service_class$ :"
  199. " GRPCProtoService<$service_class$>\n");
  200. printer.Print(
  201. "- (instancetype)initWithHost:(NSString *)host"
  202. " NS_DESIGNATED_INITIALIZER;\n");
  203. printer.Print("+ (instancetype)serviceWithHost:(NSString *)host;\n");
  204. printer.Print("@end\n");
  205. }
  206. return output;
  207. }
  208. ::grpc::string GetSource(const ServiceDescriptor *service) {
  209. ::grpc::string output;
  210. {
  211. // Scope the output stream so it closes and finalizes output to the string.
  212. grpc::protobuf::io::StringOutputStream output_stream(&output);
  213. Printer printer(&output_stream, '$');
  214. map< ::grpc::string, ::grpc::string> vars = {
  215. {"service_name", service->name()},
  216. {"service_class", ServiceClassName(service)},
  217. {"package", service->file()->package()}};
  218. printer.Print(vars, "@implementation $service_class$\n\n");
  219. printer.Print("// Designated initializer\n");
  220. printer.Print("- (instancetype)initWithHost:(NSString *)host {\n");
  221. printer.Print(
  222. vars,
  223. " return (self = [super initWithHost:host"
  224. " packageName:@\"$package$\" serviceName:@\"$service_name$\"]);\n");
  225. printer.Print("}\n\n");
  226. printer.Print(
  227. "// Override superclass initializer to disallow different"
  228. " package and service names.\n");
  229. printer.Print("- (instancetype)initWithHost:(NSString *)host\n");
  230. printer.Print(" packageName:(NSString *)packageName\n");
  231. printer.Print(" serviceName:(NSString *)serviceName {\n");
  232. printer.Print(" return [self initWithHost:host];\n");
  233. printer.Print("}\n\n");
  234. printer.Print("+ (instancetype)serviceWithHost:(NSString *)host {\n");
  235. printer.Print(" return [[self alloc] initWithHost:host];\n");
  236. printer.Print("}\n\n\n");
  237. for (int i = 0; i < service->method_count(); i++) {
  238. PrintMethodImplementations(&printer, service->method(i));
  239. }
  240. printer.Print("@end\n");
  241. }
  242. return output;
  243. }
  244. } // namespace grpc_objective_c_generator