]> git.proxmox.com Git - ceph.git/blob - ceph/src/jaegertracing/thrift/compiler/cpp/src/thrift/generate/t_dart_generator.cc
buildsys: switch source download to quincy
[ceph.git] / ceph / src / jaegertracing / thrift / compiler / cpp / src / thrift / generate / t_dart_generator.cc
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #include <sstream>
21 #include <string>
22 #include <fstream>
23 #include <iostream>
24 #include <vector>
25 #include <cctype>
26
27 #include <sys/stat.h>
28 #include <stdexcept>
29
30 #include "thrift/platform.h"
31 #include "thrift/generate/t_oop_generator.h"
32
33 using std::map;
34 using std::ostream;
35 using std::ostringstream;
36 using std::string;
37 using std::stringstream;
38 using std::vector;
39
40 static const string endl = "\n"; // avoid ostream << std::endl flushes
41 static const string endl2 = "\n\n";
42
43 /**
44 * Use the current Thrift version for static libraries. When releasing, update
45 * the version in these files.
46 * - lib/dart/pubspec.yaml
47 * - test/dart/test_client/pubspec.yaml
48 * - tutorial/dart/client/pubspec.yaml
49 * - tutorial/dart/console_client/pubspec.yaml
50 * - tutorial/dart/server/pubspec.yaml
51 * See https://thrift.apache.org/docs/committers/HowToVersion
52 */
53 static const string dart_thrift_version = THRIFT_VERSION;
54
55 /* forward declarations */
56 string initial_caps_to_underscores(string name);
57
58 /**
59 * Dart code generator
60 *
61 */
62 class t_dart_generator : public t_oop_generator {
63 public:
64 t_dart_generator(t_program* program,
65 const std::map<std::string, std::string>& parsed_options,
66 const std::string& option_string)
67 : t_oop_generator(program) {
68 (void)option_string;
69 std::map<std::string, std::string>::const_iterator iter;
70
71 library_name_ = "";
72 library_prefix_ = "";
73 package_prefix_ = "";
74 pubspec_lib_ = "";
75 for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
76 if( iter->first.compare("library_name") == 0) {
77 library_name_ = (iter->second);
78 } else if( iter->first.compare("library_prefix") == 0) {
79 library_prefix_ = (iter->second) + ".";
80 package_prefix_ = replace_all(library_prefix_, ".", "/");
81 } else if( iter->first.compare("pubspec_lib") == 0) {
82 pubspec_lib_ = (iter->second);
83 } else {
84 throw "unknown option dart:" + iter->first;
85 }
86 }
87
88 out_dir_base_ = "gen-dart";
89 }
90
91 void scope_up(std::ostream& out, std::string prefix=" ") {
92 out << prefix << "{" << endl;
93 indent_up();
94 }
95
96 void scope_down(std::ostream& out, std::string postfix=endl) {
97 indent_down();
98 indent(out) << "}" << postfix;
99 }
100
101 string replace_all(string contents, string search, string repl) {
102 string str(contents);
103
104 size_t slen = search.length();
105 size_t rlen = repl.length();
106 size_t incr = (rlen > 0) ? rlen : 1;
107
108 if (slen > 0) {
109 size_t found = str.find(search);
110 while ((found != string::npos) && (found < str.length())) {
111 str.replace(found, slen, repl);
112 found = str.find(search, found + incr);
113 }
114 }
115
116 return str;
117 }
118
119
120 /**
121 * Init and close methods
122 */
123
124 void init_generator() override;
125 void close_generator() override;
126
127 void export_class_to_library(string file_name, string class_name);
128
129 void generate_dart_library();
130 void generate_dart_pubspec();
131
132 void generate_consts(std::vector<t_const*> consts) override;
133
134 /**
135 * Program-level generation functions
136 */
137
138 void generate_typedef(t_typedef* ttypedef) override;
139 void generate_enum(t_enum* tenum) override;
140 void generate_struct(t_struct* tstruct) override;
141 void generate_xception(t_struct* txception) override;
142 void generate_service(t_service* tservice) override;
143
144 void print_const_value(std::ostream& out,
145 std::string name,
146 t_type* type,
147 t_const_value* value,
148 bool in_static,
149 bool defval = false);
150 std::string render_const_value(ostream& out,
151 std::string name,
152 t_type* type,
153 t_const_value* value);
154
155 /**
156 * Service-level generation functions
157 */
158
159 void generate_dart_struct(t_struct* tstruct, bool is_exception);
160
161 void generate_dart_struct_definition(std::ostream& out,
162 t_struct* tstruct,
163 bool is_xception = false,
164 bool is_result = false,
165 string export_file_name = "");
166 void generate_dart_struct_reader(std::ostream& out, t_struct* tstruct);
167 void generate_dart_validator(std::ostream& out, t_struct* tstruct);
168 void generate_dart_struct_result_writer(std::ostream& out, t_struct* tstruct);
169 void generate_dart_struct_writer(std::ostream& out, t_struct* tstruct);
170 void generate_dart_struct_tostring(std::ostream& out, t_struct* tstruct);
171 std::string get_dart_type_string(t_type* type);
172 void generate_generic_field_getters(std::ostream& out, t_struct* tstruct);
173 void generate_generic_field_setters(std::ostream& out, t_struct* tstruct);
174 void generate_generic_isset_method(std::ostream& out, t_struct* tstruct);
175 void generate_dart_bean_boilerplate(std::ostream& out, t_struct* tstruct);
176
177 void generate_function_helpers(t_function* tfunction);
178 std::string init_value(t_field* tfield);
179 std::string get_cap_name(std::string name);
180 std::string get_member_name(std::string name);
181 std::string get_args_class_name(std::string name);
182 std::string get_result_class_name(std::string name);
183 std::string get_file_name(std::string name);
184 std::string get_constants_class_name(std::string name);
185 std::string generate_isset_check(t_field* field);
186 std::string generate_isset_check(std::string field);
187 void generate_isset_set(ostream& out, t_field* field);
188
189 void generate_service_interface(t_service* tservice);
190 void generate_service_helpers(t_service* tservice);
191 void generate_service_client(t_service* tservice);
192 void generate_service_server(t_service* tservice);
193 void generate_process_function(t_service* tservice, t_function* tfunction);
194
195 /**
196 * Serialization constructs
197 */
198
199 void generate_deserialize_field(std::ostream& out, t_field* tfield, std::string prefix = "");
200
201 void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
202
203 void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
204
205 void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = "");
206
207 void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = "");
208
209 void generate_deserialize_list_element(std::ostream& out,
210 t_list* tlist,
211 std::string prefix = "");
212
213 void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = "");
214
215 void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
216
217 void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = "");
218
219 void generate_serialize_map_element(std::ostream& out,
220 t_map* tmap,
221 std::string iter,
222 std::string map);
223
224 void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);
225
226 void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter);
227
228 void generate_dart_doc(std::ostream& out, t_doc* tdoc);
229
230 void generate_dart_doc(std::ostream& out, t_function* tdoc);
231
232 /**
233 * Helper rendering functions
234 */
235
236 std::string find_library_name(t_program* program);
237 std::string dart_library(string file_name);
238 std::string service_imports();
239 std::string dart_thrift_imports();
240 std::string type_name(t_type* ttype);
241 std::string base_type_name(t_base_type* tbase);
242 std::string declare_field(t_field* tfield, bool init = false);
243 std::string function_signature(t_function* tfunction);
244 std::string argument_list(t_struct* tstruct);
245 std::string type_to_enum(t_type* ttype);
246 std::string get_ttype_class_name(t_type* ttype);
247
248 bool type_can_be_null(t_type* ttype) {
249 ttype = get_true_type(ttype);
250
251 return ttype->is_container() || ttype->is_struct() || ttype->is_xception()
252 || ttype->is_string();
253 }
254
255 vector<std::string> split(const string& s, char delim) {
256 vector<std::string> elems;
257 stringstream ss(s);
258 string item;
259 while (getline(ss, item, delim)) {
260 elems.push_back(item);
261 }
262 return elems;
263 }
264
265 std::string constant_name(std::string name);
266
267 private:
268 ofstream_with_content_based_conditional_update f_service_;
269
270 std::string library_name_;
271 std::string library_prefix_;
272 std::string package_prefix_;
273 std::string pubspec_lib_;
274
275 std::string base_dir_;
276 std::string src_dir_;
277 std::string library_exports_;
278 };
279
280 /**
281 * Prepares for file generation by opening up the necessary file output
282 * streams.
283 *
284 * @param tprogram The program to generate
285 */
286 void t_dart_generator::init_generator() {
287 MKDIR(get_out_dir().c_str());
288
289 if (library_name_.empty()) {
290 library_name_ = find_library_name(program_);
291 }
292
293 string subdir = get_out_dir() + "/" + library_name_;
294 MKDIR(subdir.c_str());
295 base_dir_ = subdir;
296
297 if (library_prefix_.empty()) {
298 subdir += "/lib";
299 MKDIR(subdir.c_str());
300 subdir += "/src";
301 MKDIR(subdir.c_str());
302 src_dir_ = subdir;
303 } else {
304 src_dir_ = base_dir_;
305 }
306 }
307
308 string t_dart_generator::find_library_name(t_program* program) {
309 string name = program->get_namespace("dart");
310 if (name.empty()) {
311 name = program->get_name();
312 }
313 name = replace_all(name, ".", "_");
314 name = replace_all(name, "-", "_");
315 return name;
316 }
317
318 /**
319 * The Dart library
320 *
321 * @return String of the library, e.g. "library myservice;"
322 */
323 string t_dart_generator::dart_library(string file_name) {
324 string out = "library " + library_prefix_ + library_name_;
325 if (!file_name.empty()) {
326 if (library_prefix_.empty()) {
327 out += ".src." + file_name;
328 } else {
329 out += "." + file_name;
330 }
331 }
332 return out + ";\n";
333 }
334
335 /**
336 * Prints imports for services
337 *
338 * @return List of imports for services
339 */
340 string t_dart_generator::service_imports() {
341 return "import 'dart:async';" + endl;
342 }
343
344 /**
345 * Prints standard dart imports
346 *
347 * @return List of imports necessary for thrift
348 */
349 string t_dart_generator::dart_thrift_imports() {
350 string imports = "import 'dart:typed_data' show Uint8List;" + endl +
351 "import 'package:thrift/thrift.dart';" + endl;
352
353 // add import for this library
354 if (package_prefix_.empty()) {
355 imports += "import 'package:" + library_name_ + "/" + library_name_ + ".dart';" + endl;
356 } else {
357 imports += "import 'package:" + package_prefix_ + library_name_ + ".dart';" + endl;
358 }
359
360 // add imports for included thrift files
361 const vector<t_program*>& includes = program_->get_includes();
362 for (auto include : includes) {
363 string include_name = find_library_name(include);
364 string named_import = "t_" + include_name;
365 if (package_prefix_.empty()) {
366 imports += "import 'package:" + include_name + "/" + include_name + ".dart' as " + named_import + ";" + endl;
367 } else {
368 imports += "import 'package:" + package_prefix_ + include_name + ".dart' as " + named_import + ";" + endl;
369 }
370 }
371
372 return imports;
373 }
374
375 /**
376 * Not used
377 */
378 void t_dart_generator::close_generator() {
379 generate_dart_library();
380
381 if (library_prefix_.empty()) {
382 generate_dart_pubspec();
383 }
384 }
385
386 void t_dart_generator::generate_dart_library() {
387 string f_library_name;
388 if (library_prefix_.empty()) {
389 f_library_name = base_dir_ + "/lib/" + library_name_ + ".dart";
390 } else {
391 f_library_name = get_out_dir() + "/" + library_name_ + ".dart";
392 }
393
394 ofstream_with_content_based_conditional_update f_library;
395 f_library.open(f_library_name.c_str());
396
397 f_library << autogen_comment() << endl;
398 f_library << "library " << library_prefix_ << library_name_ << ";" << endl2;
399 f_library << library_exports_;
400
401 f_library.close();
402 }
403
404 void t_dart_generator::export_class_to_library(string file_name, string class_name) {
405 string subdir;
406 if (library_prefix_.empty()) {
407 subdir = "src";
408 } else {
409 subdir = library_name_;
410 }
411 library_exports_ += "export '" + subdir + "/" + file_name + ".dart' show " + class_name + ";" + endl;
412 }
413
414 void t_dart_generator::generate_dart_pubspec() {
415 string f_pubspec_name = base_dir_ + "/pubspec.yaml";
416 ofstream_with_content_based_conditional_update f_pubspec;
417 f_pubspec.open(f_pubspec_name.c_str());
418
419 indent(f_pubspec) << "name: " << library_name_ << endl;
420 indent(f_pubspec) << "version: 0.0.1" << endl;
421 indent(f_pubspec) << "description: Autogenerated by Thrift Compiler" << endl;
422 f_pubspec << endl;
423
424 indent(f_pubspec) << "environment:" << endl;
425 indent_up();
426 indent(f_pubspec) << "sdk: '>=1.24.3 <3.0.0'" << endl;
427 indent_down();
428 f_pubspec << endl;
429
430 indent(f_pubspec) << "dependencies:" << endl;
431 indent_up();
432
433 if (pubspec_lib_.empty()) {
434 // default to relative path within working directory, which works for tests
435 indent(f_pubspec) << "thrift: # ^" << dart_thrift_version << endl;
436 indent_up();
437 indent(f_pubspec) << "path: ../../../../lib/dart" << endl;
438 indent_down();
439 } else {
440 const vector<std::string> lines = split(pubspec_lib_, '|');
441 for (const auto & line : lines) {
442 indent(f_pubspec) << line << endl;
443 }
444 }
445
446 // add included thrift files as dependencies
447 const vector<t_program*>& includes = program_->get_includes();
448 for (auto include : includes) {
449 string include_name = find_library_name(include);
450 indent(f_pubspec) << include_name << ":" << endl;
451 indent_up();
452 indent(f_pubspec) << "path: ../" << include_name << endl;
453 indent_down();
454 }
455
456 indent_down();
457 f_pubspec << endl;
458
459 f_pubspec.close();
460 }
461
462 /**
463 * Not used
464 *
465 * @param ttypedef The type definition
466 */
467 void t_dart_generator::generate_typedef(t_typedef* ttypedef) {
468 (void)ttypedef;
469 }
470
471 /**
472 * Enums are a class with a set of static constants.
473 *
474 * @param tenum The enumeration
475 */
476 void t_dart_generator::generate_enum(t_enum* tenum) {
477 // Make output file
478 string file_name = get_file_name(tenum->get_name());
479
480 string f_enum_name = src_dir_ + "/" + file_name + ".dart";
481 ofstream_with_content_based_conditional_update f_enum;
482 f_enum.open(f_enum_name.c_str());
483
484 // Comment and add library
485 f_enum << autogen_comment() << dart_library(file_name) << endl;
486
487 string class_name = tenum->get_name();
488 export_class_to_library(file_name, class_name);
489 f_enum << "class " << class_name;
490 scope_up(f_enum);
491
492 vector<t_enum_value*> constants = tenum->get_constants();
493 vector<t_enum_value*>::iterator c_iter;
494 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
495 int value = (*c_iter)->get_value();
496 indent(f_enum) << "static const int " << (*c_iter)->get_name() << " = " << value << ";"
497 << endl;
498 }
499
500 // Create a static Set with all valid values for this enum
501 f_enum << endl;
502
503 indent(f_enum) << "static final Set<int> VALID_VALUES = new Set.from([" << endl;
504 indent_up();
505 bool firstValue = true;
506 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
507 // populate set
508 indent(f_enum) << (firstValue ? "" : ", ");
509 f_enum << (*c_iter)->get_name() << endl;
510 firstValue = false;
511 }
512 indent_down();
513 indent(f_enum) << "]);" << endl;
514
515 indent(f_enum) << "static final Map<int, String> VALUES_TO_NAMES = {" << endl;
516 indent_up();
517 firstValue = true;
518 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
519 indent(f_enum) << (firstValue ? "" : ", ");
520 f_enum << (*c_iter)->get_name() << ": '" << (*c_iter)->get_name() << "'" << endl;
521 firstValue = false;
522 }
523 indent_down();
524 indent(f_enum) << "};" << endl;
525
526 scope_down(f_enum); // end class
527
528 f_enum.close();
529 }
530
531 /**
532 * Generates a class that holds all the constants.
533 */
534 void t_dart_generator::generate_consts(std::vector<t_const*> consts) {
535 if (consts.empty()) {
536 return;
537 }
538
539 string class_name = get_constants_class_name(program_name_);
540 string file_name = get_file_name(class_name);
541
542 string f_consts_name = src_dir_ + "/" + file_name + ".dart";
543 ofstream_with_content_based_conditional_update f_consts;
544 f_consts.open(f_consts_name.c_str());
545
546 // Print header
547 f_consts << autogen_comment() << dart_library(file_name) << endl;
548 f_consts << dart_thrift_imports() << endl;
549
550 export_class_to_library(file_name, class_name);
551 indent(f_consts) << "class " << class_name;
552 scope_up(f_consts);
553
554 vector<t_const*>::iterator c_iter;
555 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
556 print_const_value(f_consts,
557 (*c_iter)->get_name(),
558 (*c_iter)->get_type(),
559 (*c_iter)->get_value(),
560 false);
561 f_consts << endl;
562 }
563
564 scope_down(f_consts);
565
566 f_consts.close();
567 }
568
569 void t_dart_generator::print_const_value(std::ostream& out,
570 string name,
571 t_type* type,
572 t_const_value* value,
573 bool in_static,
574 bool defval) {
575 type = get_true_type(type);
576
577 indent(out);
578 if (!defval) {
579 out << (in_static ? "var " : "static final ");
580 }
581 if (type->is_base_type()) {
582 if (!defval) {
583 out << type_name(type) << " ";
584 }
585 string v2 = render_const_value(out, name, type, value);
586 out << name;
587 out << " = " << v2 << ";" << endl << endl;
588 } else if (type->is_enum()) {
589 if (!defval) {
590 out << type_name(type) << " ";
591 }
592 out << name;
593 out << " = " << value->get_integer() << ";" << endl << endl;
594 } else if (type->is_struct() || type->is_xception()) {
595 const vector<t_field*>& fields = ((t_struct*)type)->get_members();
596 vector<t_field*>::const_iterator f_iter;
597 const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
598 map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
599 out << type_name(type) << " " << name << " = new " << type_name(type) << "()";
600 indent_up();
601 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
602 t_type* field_type = NULL;
603 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
604 if ((*f_iter)->get_name() == v_iter->first->get_string()) {
605 field_type = (*f_iter)->get_type();
606 }
607 }
608 if (field_type == NULL) {
609 throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
610 }
611 string val = render_const_value(out, name, field_type, v_iter->second);
612 out << endl;
613 indent(out) << ".." << v_iter->first->get_string() << " = " << val;
614 }
615 indent_down();
616 out << ";" << endl;
617 } else if (type->is_map()) {
618 if (!defval) {
619 out << type_name(type) << " ";
620 }
621 out << name << " =";
622 scope_up(out);
623
624 t_type* ktype = ((t_map*)type)->get_key_type();
625 t_type* vtype = ((t_map*)type)->get_val_type();
626 const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
627 map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
628
629 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
630 string key = render_const_value(out, name, ktype, v_iter->first);
631 string val = render_const_value(out, name, vtype, v_iter->second);
632 indent(out) << key << ": " << val << "," << endl;
633 }
634 scope_down(out, ";" + endl);
635
636 out << endl;
637 } else if (type->is_list() || type->is_set()) {
638 if (!defval) {
639 out << type_name(type) << " ";
640 }
641 out << name << " = ";
642 t_type* etype;
643 if (type->is_list()) {
644 out << "[" << endl;
645 etype = ((t_list*)type)->get_elem_type();
646 } else {
647 out << "new " << type_name(type) << ".from([" << endl;
648 etype = ((t_set*)type)->get_elem_type();
649 }
650 const vector<t_const_value*>& val = value->get_list();
651 vector<t_const_value*>::const_iterator v_iter;
652
653 indent_up();
654 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
655 string val = render_const_value(out, name, etype, *v_iter);
656 indent(out) << val << "," << endl;
657 }
658 indent_down();
659
660 if (type->is_list()) {
661 indent(out) << "];" << endl;
662 } else {
663 indent(out) << "]);" << endl;
664 }
665
666 } else {
667 throw "compiler error: no const of type " + type->get_name();
668 }
669 }
670
671 string t_dart_generator::render_const_value(ostream& out,
672 string name,
673 t_type* type,
674 t_const_value* value) {
675 (void)name;
676 type = get_true_type(type);
677 std::ostringstream render;
678
679 if (type->is_base_type()) {
680 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
681 switch (tbase) {
682 case t_base_type::TYPE_STRING:
683 render << "'" << get_escaped_string(value) << "'";
684 break;
685 case t_base_type::TYPE_BOOL:
686 render << ((value->get_integer() > 0) ? "true" : "false");
687 break;
688 case t_base_type::TYPE_I8:
689 case t_base_type::TYPE_I16:
690 case t_base_type::TYPE_I32:
691 case t_base_type::TYPE_I64:
692 render << value->get_integer();
693 break;
694 case t_base_type::TYPE_DOUBLE:
695 if (value->get_type() == t_const_value::CV_INTEGER) {
696 render << value->get_integer();
697 } else {
698 render << value->get_double();
699 }
700 break;
701 default:
702 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
703 }
704 } else if (type->is_enum()) {
705 render << value->get_integer();
706 } else {
707 string t = tmp("tmp");
708 print_const_value(out, t, type, value, true);
709 out << endl;
710 render << t;
711 }
712
713 return render.str();
714 }
715
716 /**
717 * Generates a struct definition for a thrift data type. This is a class
718 * with data members, read(), write(), and an inner Isset class.
719 *
720 * @param tstruct The struct definition
721 */
722 void t_dart_generator::generate_struct(t_struct* tstruct) {
723 generate_dart_struct(tstruct, false);
724 }
725
726 /**
727 * Exceptions are structs, but they inherit from Exception
728 *
729 * @param tstruct The struct definition
730 */
731 void t_dart_generator::generate_xception(t_struct* txception) {
732 generate_dart_struct(txception, true);
733 }
734
735 /**
736 * Dart struct definition.
737 *
738 * @param tstruct The struct definition
739 */
740 void t_dart_generator::generate_dart_struct(t_struct* tstruct, bool is_exception) {
741 string file_name = get_file_name(tstruct->get_name());
742 string f_struct_name = src_dir_ + "/" + file_name + ".dart";
743 ofstream_with_content_based_conditional_update f_struct;
744 f_struct.open(f_struct_name.c_str());
745
746 f_struct << autogen_comment() << dart_library(file_name) << endl;
747
748 string imports;
749
750 f_struct << dart_thrift_imports() << endl;
751
752 generate_dart_struct_definition(f_struct, tstruct, is_exception, false, file_name);
753
754 f_struct.close();
755 }
756
757 /**
758 * Dart struct definition. This has various parameters, as it could be
759 * generated standalone or inside another class as a helper. If it
760 * is a helper than it is a static class.
761 *
762 * @param tstruct The struct definition
763 * @param is_exception Is this an exception?
764 * @param in_class If inside a class, needs to be static class
765 * @param is_result If this is a result it needs a different writer
766 */
767 void t_dart_generator::generate_dart_struct_definition(ostream& out,
768 t_struct* tstruct,
769 bool is_exception,
770 bool is_result,
771 string export_file_name) {
772 generate_dart_doc(out, tstruct);
773
774 string class_name = tstruct->get_name();
775 if (!export_file_name.empty()) {
776 export_class_to_library(export_file_name, class_name);
777 }
778 indent(out) << "class " << class_name << " ";
779
780 out << "implements TBase";
781 if (is_exception) {
782 out << ", Exception ";
783 }
784 scope_up(out);
785
786 indent(out) << "static final TStruct _STRUCT_DESC = new TStruct(\"" << class_name
787 << "\");" << endl;
788
789 // Members are public for -dart, private for -dartbean
790 const vector<t_field*>& members = tstruct->get_members();
791 vector<t_field*>::const_iterator m_iter;
792
793 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
794 indent(out) << "static final TField _" << constant_name((*m_iter)->get_name())
795 << "_FIELD_DESC = new TField(\"" << (*m_iter)->get_name() << "\", "
796 << type_to_enum((*m_iter)->get_type()) << ", " << (*m_iter)->get_key() << ");"
797 << endl;
798 }
799
800 out << endl;
801
802 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
803 generate_dart_doc(out, *m_iter);
804 indent(out) << type_name((*m_iter)->get_type()) + " _"
805 << get_member_name((*m_iter)->get_name()) << init_value(*m_iter) << ";" << endl;
806
807 indent(out) << "static const int " << upcase_string((*m_iter)->get_name())
808 << " = " << (*m_iter)->get_key() << ";" << endl;
809 }
810
811 out << endl;
812
813 // Inner Isset class
814 if (members.size() > 0) {
815 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
816 if (!type_can_be_null((*m_iter)->get_type())) {
817 string field_name = get_member_name((*m_iter)->get_name());
818 indent(out) << "bool __isset_" << field_name << " = false;" << endl;
819 }
820 }
821 }
822
823 out << endl;
824
825 // Default constructor
826 indent(out) << tstruct->get_name() << "()";
827 scope_up(out);
828 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
829 t_type* t = get_true_type((*m_iter)->get_type());
830 if ((*m_iter)->get_value() != NULL) {
831 print_const_value(out,
832 "this." + get_member_name((*m_iter)->get_name()),
833 t,
834 (*m_iter)->get_value(),
835 true,
836 true);
837 }
838 }
839 scope_down(out);
840 out << endl;
841
842 generate_dart_bean_boilerplate(out, tstruct);
843 generate_generic_field_getters(out, tstruct);
844 generate_generic_field_setters(out, tstruct);
845 generate_generic_isset_method(out, tstruct);
846
847 generate_dart_struct_reader(out, tstruct);
848 if (is_result) {
849 generate_dart_struct_result_writer(out, tstruct);
850 } else {
851 generate_dart_struct_writer(out, tstruct);
852 }
853 generate_dart_struct_tostring(out, tstruct);
854 generate_dart_validator(out, tstruct);
855 scope_down(out);
856 out << endl;
857 }
858
859 /**
860 * Generates a function to read all the fields of the struct.
861 *
862 * @param tstruct The struct definition
863 */
864 void t_dart_generator::generate_dart_struct_reader(ostream& out, t_struct* tstruct) {
865 indent(out) << "read(TProtocol iprot)";
866 scope_up(out);
867
868 const vector<t_field*>& fields = tstruct->get_members();
869 vector<t_field*>::const_iterator f_iter;
870
871 // Declare stack tmp variables and read struct header
872 indent(out) << "TField field;" << endl;
873 indent(out) << "iprot.readStructBegin();" << endl;
874
875 // Loop over reading in fields
876 indent(out) << "while (true)";
877 scope_up(out);
878
879 // Read beginning field marker
880 indent(out) << "field = iprot.readFieldBegin();" << endl;
881
882 // Check for field STOP marker and break
883 indent(out) << "if (field.type == TType.STOP)";
884 scope_up(out);
885 indent(out) << "break;" << endl;
886 scope_down(out);
887
888 // Switch statement on the field we are reading
889 indent(out) << "switch (field.id)";
890 scope_up(out);
891
892 // Generate deserialization code for known cases
893 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
894 indent(out) << "case " << upcase_string((*f_iter)->get_name()) << ":" << endl;
895 indent_up();
896
897 indent(out) << "if (field.type == " << type_to_enum((*f_iter)->get_type()) << ")";
898 scope_up(out);
899
900 generate_deserialize_field(out, *f_iter, "this.");
901 generate_isset_set(out, *f_iter);
902
903 scope_down(out, " else");
904 scope_up(out);
905 indent(out) << "TProtocolUtil.skip(iprot, field.type);" << endl;
906 scope_down(out);
907
908 indent(out) << "break;" << endl;
909 indent_down();
910 }
911
912 // In the default case we skip the field
913 indent(out) << "default:" << endl;
914 indent_up();
915 indent(out) << "TProtocolUtil.skip(iprot, field.type);" << endl;
916 indent(out) << "break;" << endl;
917 indent_down();
918
919 scope_down(out);
920
921 // Read field end marker
922 indent(out) << "iprot.readFieldEnd();" << endl;
923
924 scope_down(out);
925
926 indent(out) << "iprot.readStructEnd();" << endl2;
927
928 // in non-beans style, check for required fields of primitive type
929 // (which can be checked here but not in the general validate method)
930 indent(out) << "// check for required fields of primitive type, which can't be "
931 "checked in the validate method" << endl;
932 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
933 if ((*f_iter)->get_req() == t_field::T_REQUIRED && !type_can_be_null((*f_iter)->get_type())) {
934 string field_name = get_member_name((*f_iter)->get_name());
935 indent(out) << "if (!__isset_" << field_name << ")";
936 scope_up(out);
937 indent(out) << " throw new TProtocolError(TProtocolErrorType.UNKNOWN, \"Required field '"
938 << field_name
939 << "' was not found in serialized data! Struct: \" + toString());" << endl;
940 scope_down(out, endl2);
941 }
942 }
943
944 // performs various checks (e.g. check that all required fields are set)
945 indent(out) << "validate();" << endl;
946
947 scope_down(out, endl2);
948 }
949
950 // generates dart method to perform various checks
951 // (e.g. check that all required fields are set)
952 void t_dart_generator::generate_dart_validator(ostream& out, t_struct* tstruct) {
953 indent(out) << "validate()";
954 scope_up(out);
955
956 const vector<t_field*>& fields = tstruct->get_members();
957 vector<t_field*>::const_iterator f_iter;
958
959 indent(out) << "// check for required fields" << endl;
960 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
961 if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
962 string field_name = get_member_name((*f_iter)->get_name());
963 if (type_can_be_null((*f_iter)->get_type())) {
964 indent(out) << "if (" << field_name << " == null)";
965 scope_up(out);
966 indent(out) << "throw new TProtocolError(TProtocolErrorType.UNKNOWN, \"Required field '"
967 << field_name << "' was not present! Struct: \" + toString());"
968 << endl;
969 scope_down(out);
970 } else {
971 indent(out) << "// alas, we cannot check '" << field_name
972 << "' because it's a primitive and you chose the non-beans generator." << endl;
973 }
974 }
975 }
976
977 // check that fields of type enum have valid values
978 indent(out) << "// check that fields of type enum have valid values" << endl;
979 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
980 t_field* field = (*f_iter);
981 t_type* type = field->get_type();
982 // if field is an enum, check that its value is valid
983 if (type->is_enum()) {
984 string field_name = get_member_name(field->get_name());
985 indent(out) << "if (" << generate_isset_check(field) << " && !" << get_ttype_class_name(type)
986 << ".VALID_VALUES.contains(" << field_name << "))";
987 scope_up(out);
988 indent(out) << "throw new TProtocolError(TProtocolErrorType.UNKNOWN, \"The field '"
989 << field_name << "' has been assigned the invalid value "
990 << "$" << field_name << "\");" << endl;
991 scope_down(out);
992 }
993 }
994
995 scope_down(out, endl2);
996 }
997
998 /**
999 * Generates a function to write all the fields of the struct
1000 *
1001 * @param tstruct The struct definition
1002 */
1003 void t_dart_generator::generate_dart_struct_writer(ostream& out, t_struct* tstruct) {
1004 out << indent() << "write(TProtocol oprot)";
1005 scope_up(out);
1006
1007 const vector<t_field*>& fields = tstruct->get_sorted_members();
1008 vector<t_field*>::const_iterator f_iter;
1009
1010 // performs various checks (e.g. check that all required fields are set)
1011 indent(out) << "validate();" << endl2;
1012
1013 indent(out) << "oprot.writeStructBegin(_STRUCT_DESC);" << endl;
1014
1015 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1016 string field_name = get_member_name((*f_iter)->get_name());
1017 bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL;
1018 if (could_be_unset) {
1019 indent(out) << "if (" << generate_isset_check(*f_iter) << ")";
1020 scope_up(out);
1021 }
1022 bool null_allowed = type_can_be_null((*f_iter)->get_type());
1023 if (null_allowed) {
1024 indent(out) << "if (this." << field_name << " != null)";
1025 scope_up(out);
1026 }
1027
1028 indent(out) << "oprot.writeFieldBegin(_" << constant_name((*f_iter)->get_name())
1029 << "_FIELD_DESC);" << endl;
1030
1031 // Write field contents
1032 generate_serialize_field(out, *f_iter, "this.");
1033
1034 // Write field closer
1035 indent(out) << "oprot.writeFieldEnd();" << endl;
1036
1037 if (null_allowed) {
1038 scope_down(out);
1039 }
1040 if (could_be_unset) {
1041 scope_down(out);
1042 }
1043 }
1044 // Write the struct map
1045 indent(out) << "oprot.writeFieldStop();" << endl << indent() << "oprot.writeStructEnd();"
1046 << endl;
1047
1048 scope_down(out, endl2);
1049 }
1050
1051 /**
1052 * Generates a function to write all the fields of the struct,
1053 * which is a function result. These fields are only written
1054 * if they are set in the Isset array, and only one of them
1055 * can be set at a time.
1056 *
1057 * @param tstruct The struct definition
1058 */
1059 void t_dart_generator::generate_dart_struct_result_writer(ostream& out, t_struct* tstruct) {
1060 indent(out) << "write(TProtocol oprot)";
1061 scope_up(out);
1062
1063 const vector<t_field*>& fields = tstruct->get_sorted_members();
1064 vector<t_field*>::const_iterator f_iter;
1065
1066 indent(out) << "oprot.writeStructBegin(_STRUCT_DESC);" << endl2;
1067
1068 bool first = true;
1069 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1070 if (first) {
1071 first = false;
1072 indent(out) << "if ";
1073 } else {
1074 out << " else if ";
1075 }
1076
1077 out << "(this." << generate_isset_check(*f_iter) << ")";
1078 scope_up(out);
1079
1080 indent(out) << "oprot.writeFieldBegin(_" << constant_name((*f_iter)->get_name())
1081 << "_FIELD_DESC);" << endl;
1082
1083 // Write field contents
1084 generate_serialize_field(out, *f_iter, "this.");
1085
1086 // Write field closer
1087 indent(out) << "oprot.writeFieldEnd();" << endl;
1088
1089 scope_down(out, "");
1090 }
1091 out << endl;
1092
1093 // Write the struct map
1094 indent(out) << "oprot.writeFieldStop();" << endl << indent()
1095 << "oprot.writeStructEnd();" << endl;
1096
1097 scope_down(out, endl2);
1098 }
1099
1100 void t_dart_generator::generate_generic_field_getters(std::ostream& out,
1101 t_struct* tstruct) {
1102 // create the getter
1103 indent(out) << "getFieldValue(int fieldID)";
1104 scope_up(out);
1105
1106 indent(out) << "switch (fieldID)";
1107 scope_up(out);
1108
1109 const vector<t_field*>& fields = tstruct->get_members();
1110 vector<t_field*>::const_iterator f_iter;
1111 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1112 t_field* field = *f_iter;
1113 std::string field_name = get_member_name(field->get_name());
1114
1115 indent(out) << "case " << upcase_string(field_name) << ":" << endl;
1116 indent_up();
1117 indent(out) << "return this." << field_name << ";" << endl;
1118 indent_down();
1119 }
1120
1121 indent(out) << "default:" << endl;
1122 indent_up();
1123 indent(out) << "throw new ArgumentError(\"Field $fieldID doesn't exist!\");" << endl;
1124 indent_down();
1125
1126 scope_down(out); // switch
1127 scope_down(out, endl2); // method
1128 }
1129
1130 void t_dart_generator::generate_generic_field_setters(std::ostream& out,
1131 t_struct* tstruct) {
1132
1133 // create the setter
1134 indent(out) << "setFieldValue(int fieldID, Object value)";
1135 scope_up(out);
1136
1137 indent(out) << "switch (fieldID)";
1138 scope_up(out);
1139
1140 // build up the bodies of both the getter and setter at once
1141 const vector<t_field*>& fields = tstruct->get_members();
1142 vector<t_field*>::const_iterator f_iter;
1143 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1144 t_field* field = *f_iter;
1145 std::string field_name = get_member_name(field->get_name());
1146
1147 indent(out) << "case " << upcase_string(field_name) << ":" << endl;
1148 indent_up();
1149
1150 indent(out) << "if (value == null)";
1151 scope_up(out);
1152 indent(out) << "unset" << get_cap_name(field_name) << "();" << endl;
1153
1154 scope_down(out, " else");
1155 scope_up(out);
1156 indent(out) << "this." << field_name << " = value;" << endl;
1157 scope_down(out);
1158
1159 indent(out) << "break;" << endl;
1160
1161 indent_down();
1162 out << endl;
1163 }
1164
1165 indent(out) << "default:" << endl;
1166 indent_up();
1167 indent(out) << "throw new ArgumentError(\"Field $fieldID doesn't exist!\");" << endl;
1168 indent_down();
1169
1170 scope_down(out); // switch
1171 scope_down(out, endl2); // method
1172 }
1173
1174 // Creates a generic isSet method that takes the field number as argument
1175 void t_dart_generator::generate_generic_isset_method(std::ostream& out, t_struct* tstruct) {
1176 const vector<t_field*>& fields = tstruct->get_members();
1177 vector<t_field*>::const_iterator f_iter;
1178
1179 // create the isSet method
1180 indent(out) << "// Returns true if field corresponding to fieldID is set (has been assigned a "
1181 "value) and false otherwise" << endl;
1182 indent(out) << "bool isSet(int fieldID)";
1183 scope_up(out);
1184
1185 indent(out) << "switch (fieldID)";
1186 scope_up(out);
1187
1188 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1189 t_field* field = *f_iter;
1190 indent(out) << "case " << upcase_string(field->get_name()) << ":" << endl;
1191 indent_up();
1192 indent(out) << "return " << generate_isset_check(field) << ";" << endl;
1193 indent_down();
1194 }
1195
1196 indent(out) << "default:" << endl;
1197 indent_up();
1198 indent(out) << "throw new ArgumentError(\"Field $fieldID doesn't exist!\");" << endl;
1199 indent_down();
1200
1201 scope_down(out); // switch
1202 scope_down(out, endl2); // method
1203 }
1204
1205 /**
1206 * Generates a set of Dart Bean boilerplate functions (setters, getters, etc.)
1207 * for the given struct.
1208 *
1209 * @param tstruct The struct definition
1210 */
1211 void t_dart_generator::generate_dart_bean_boilerplate(ostream& out,
1212 t_struct* tstruct) {
1213 const vector<t_field*>& fields = tstruct->get_members();
1214 vector<t_field*>::const_iterator f_iter;
1215 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1216 t_field* field = *f_iter;
1217 t_type* type = get_true_type(field->get_type());
1218 std::string field_name = get_member_name(field->get_name());
1219 std::string cap_name = get_cap_name(field_name);
1220
1221 indent(out) << "// " << field_name << endl;
1222
1223 // Simple getter
1224 generate_dart_doc(out, field);
1225 indent(out) << type_name(type) << " get " << field_name << " => this._" << field_name << ";" << endl2;
1226
1227 // Simple setter
1228 generate_dart_doc(out, field);
1229 indent(out) << "set " << field_name << "(" << type_name(type) << " " << field_name << ")";
1230 scope_up(out);
1231 indent(out) << "this._" << field_name << " = " << field_name << ";" << endl;
1232 generate_isset_set(out, field);
1233 scope_down(out, endl2);
1234
1235 // isSet method
1236 indent(out) << "bool is" << get_cap_name("set") << cap_name << "()";
1237 if (type_can_be_null(type)) {
1238 out << " => this." << field_name << " != null;" << endl2;
1239 } else {
1240 out << " => this.__isset_" << field_name << ";" << endl2;
1241 }
1242
1243 // Unsetter
1244 indent(out) << "unset" << cap_name << "()";
1245 scope_up(out);
1246 if (type_can_be_null(type)) {
1247 indent(out) << "this." << field_name << " = null;" << endl;
1248 } else {
1249 indent(out) << "this.__isset_" << field_name << " = false;" << endl;
1250 }
1251 scope_down(out, endl2);
1252 }
1253 }
1254
1255 /**
1256 * Generates a toString() method for the given struct
1257 *
1258 * @param tstruct The struct definition
1259 */
1260 void t_dart_generator::generate_dart_struct_tostring(ostream& out,
1261 t_struct* tstruct) {
1262 indent(out) << "String toString()";
1263 scope_up(out);
1264
1265 indent(out) << "StringBuffer ret = new StringBuffer(\""
1266 << tstruct->get_name() << "(\");" << endl2;
1267
1268 const vector<t_field*>& fields = tstruct->get_members();
1269 vector<t_field*>::const_iterator f_iter;
1270
1271 bool first = true;
1272 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1273 bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL;
1274 if (could_be_unset) {
1275 indent(out) << "if (" << generate_isset_check(*f_iter) << ")";
1276 scope_up(out);
1277 }
1278
1279 t_field* field = (*f_iter);
1280 std::string field_name = get_member_name(field->get_name());
1281
1282 if (!first) {
1283 indent(out) << "ret.write(\", \");" << endl;
1284 }
1285 indent(out) << "ret.write(\"" << field_name << ":\");" << endl;
1286 bool can_be_null = type_can_be_null(field->get_type());
1287 if (can_be_null) {
1288 indent(out) << "if (this." << field_name << " == null)";
1289 scope_up(out);
1290 indent(out) << "ret.write(\"null\");" << endl;
1291 scope_down(out, " else");
1292 scope_up(out);
1293 }
1294
1295 if (field->get_type()->is_binary()) {
1296 indent(out) << "ret.write(\"BINARY\");" << endl;
1297 } else if (field->get_type()->is_enum()) {
1298 indent(out) << "String " << field_name << "_name = "
1299 << get_ttype_class_name(field->get_type())
1300 << ".VALUES_TO_NAMES[this." << field_name << "];" << endl;
1301 indent(out) << "if (" << field_name << "_name != null)";
1302 scope_up(out);
1303 indent(out) << "ret.write(" << field_name << "_name);" << endl;
1304 indent(out) << "ret.write(\" (\");" << endl;
1305 scope_down(out);
1306 indent(out) << "ret.write(this." << field_name << ");" << endl;
1307 indent(out) << "if (" << field_name << "_name != null)";
1308 scope_up(out);
1309 indent(out) << "ret.write(\")\");" << endl;
1310 scope_down(out);
1311 } else {
1312 indent(out) << "ret.write(this." << field_name << ");" << endl;
1313 }
1314
1315 if (can_be_null) {
1316 scope_down(out);
1317 }
1318 if (could_be_unset) {
1319 scope_down(out);
1320 }
1321
1322 out << endl;
1323 first = false;
1324 }
1325
1326 indent(out) << "ret.write(\")\");" << endl2;
1327
1328 indent(out) << "return ret.toString();" << endl;
1329
1330 scope_down(out, endl2);
1331 }
1332
1333 /**
1334 * Returns a string with the dart representation of the given thrift type
1335 * (e.g. for the type struct it returns "TType.STRUCT")
1336 */
1337 std::string t_dart_generator::get_dart_type_string(t_type* type) {
1338 if (type->is_list()) {
1339 return "TType.LIST";
1340 } else if (type->is_map()) {
1341 return "TType.MAP";
1342 } else if (type->is_set()) {
1343 return "TType.SET";
1344 } else if (type->is_struct() || type->is_xception()) {
1345 return "TType.STRUCT";
1346 } else if (type->is_enum()) {
1347 return "TType.I32";
1348 } else if (type->is_typedef()) {
1349 return get_dart_type_string(((t_typedef*)type)->get_type());
1350 } else if (type->is_base_type()) {
1351 switch (((t_base_type*)type)->get_base()) {
1352 case t_base_type::TYPE_VOID:
1353 return "TType.VOID";
1354 break;
1355 case t_base_type::TYPE_STRING:
1356 return "TType.STRING";
1357 break;
1358 case t_base_type::TYPE_BOOL:
1359 return "TType.BOOL";
1360 break;
1361 case t_base_type::TYPE_I8:
1362 return "TType.BYTE";
1363 break;
1364 case t_base_type::TYPE_I16:
1365 return "TType.I16";
1366 break;
1367 case t_base_type::TYPE_I32:
1368 return "TType.I32";
1369 break;
1370 case t_base_type::TYPE_I64:
1371 return "TType.I64";
1372 break;
1373 case t_base_type::TYPE_DOUBLE:
1374 return "TType.DOUBLE";
1375 break;
1376 default:
1377 throw std::runtime_error("Unknown thrift type \"" + type->get_name()
1378 + "\" passed to t_dart_generator::get_dart_type_string!");
1379 break; // This should never happen!
1380 }
1381 } else {
1382 throw std::runtime_error(
1383 "Unknown thrift type \"" + type->get_name()
1384 + "\" passed to t_dart_generator::get_dart_type_string!"); // This should never happen!
1385 }
1386 }
1387
1388 void t_dart_generator::generate_service(t_service* tservice) {
1389 string file_name = get_file_name(service_name_);
1390 string f_service_name = src_dir_ + "/" + file_name + ".dart";
1391 f_service_.open(f_service_name.c_str());
1392
1393 f_service_ << autogen_comment() << dart_library(file_name) << endl;
1394 f_service_ << service_imports() << dart_thrift_imports() << endl;
1395 f_service_ << endl;
1396
1397 generate_service_interface(tservice);
1398 generate_service_client(tservice);
1399 generate_service_server(tservice);
1400 generate_service_helpers(tservice);
1401
1402 f_service_.close();
1403 }
1404
1405 /**
1406 * Generates a service interface definition.
1407 *
1408 * @param tservice The service to generate a header definition for
1409 */
1410 void t_dart_generator::generate_service_interface(t_service* tservice) {
1411 string extends_iface = "";
1412 if (tservice->get_extends() != NULL) {
1413 extends_iface = " extends " + get_ttype_class_name(tservice->get_extends());
1414 }
1415
1416 generate_dart_doc(f_service_, tservice);
1417
1418 string class_name = service_name_;
1419 export_class_to_library(get_file_name(service_name_), class_name);
1420 indent(f_service_) << "abstract class " << class_name << extends_iface;
1421 scope_up(f_service_);
1422
1423 vector<t_function*> functions = tservice->get_functions();
1424 vector<t_function*>::iterator f_iter;
1425 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1426 f_service_ << endl;
1427 generate_dart_doc(f_service_, *f_iter);
1428 indent(f_service_) << function_signature(*f_iter) << ";" << endl;
1429 }
1430
1431 scope_down(f_service_, endl2);
1432 }
1433
1434 /**
1435 * Generates structs for all the service args and return types
1436 *
1437 * @param tservice The service
1438 */
1439 void t_dart_generator::generate_service_helpers(t_service* tservice) {
1440 vector<t_function*> functions = tservice->get_functions();
1441 vector<t_function*>::iterator f_iter;
1442 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1443 t_struct* ts = (*f_iter)->get_arglist();
1444 generate_dart_struct_definition(f_service_, ts, false, false);
1445 generate_function_helpers(*f_iter);
1446 }
1447 }
1448
1449 /**
1450 * Generates a service client definition.
1451 *
1452 * @param tservice The service to generate a server for.
1453 */
1454 void t_dart_generator::generate_service_client(t_service* tservice) {
1455 string extends = "";
1456 string extends_client = "";
1457 if (tservice->get_extends() != NULL) {
1458 extends = get_ttype_class_name(tservice->get_extends());
1459 extends_client = " extends " + extends + "Client";
1460 }
1461
1462 string class_name = service_name_ + "Client";
1463 export_class_to_library(get_file_name(service_name_), class_name);
1464 indent(f_service_) << "class " << class_name << extends_client
1465 << " implements " << service_name_;
1466 scope_up(f_service_);
1467 f_service_ << endl;
1468
1469 indent(f_service_) << class_name << "(TProtocol iprot, [TProtocol oprot = null])";
1470
1471 if (!extends.empty()) {
1472 indent_up();
1473 f_service_ << endl;
1474 indent(f_service_) << ": super(iprot, oprot);" << endl;
1475 indent_down();
1476 } else {
1477 scope_up(f_service_);
1478 indent(f_service_) << "_iprot = iprot;" << endl;
1479 indent(f_service_) << "_oprot = (oprot == null) ? iprot : oprot;" << endl;
1480 scope_down(f_service_);
1481 }
1482 f_service_ << endl;
1483
1484 if (extends.empty()) {
1485 indent(f_service_) << "TProtocol _iprot;" << endl2;
1486 indent(f_service_) << "TProtocol get iprot => _iprot;" << endl2;
1487 indent(f_service_) << "TProtocol _oprot;" << endl2;
1488 indent(f_service_) << "TProtocol get oprot => _oprot;" << endl2;
1489 indent(f_service_) << "int _seqid = 0;" << endl2;
1490 indent(f_service_) << "int get seqid => _seqid;" << endl2;
1491 indent(f_service_) << "int nextSeqid() => ++_seqid;" << endl2;
1492 }
1493
1494 // Generate client method implementations
1495 vector<t_function*> functions = tservice->get_functions();
1496 vector<t_function*>::const_iterator f_iter;
1497 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1498 // Open function
1499 indent(f_service_) << function_signature(*f_iter) << " async";
1500 scope_up(f_service_);
1501
1502 // Get the struct of function call params
1503 t_struct* arg_struct = (*f_iter)->get_arglist();
1504
1505 string argsname = get_args_class_name((*f_iter)->get_name());
1506 vector<t_field*>::const_iterator fld_iter;
1507 const vector<t_field*>& fields = arg_struct->get_members();
1508
1509 // Serialize the request
1510 indent(f_service_) << "oprot.writeMessageBegin(new TMessage(\"" << (*f_iter)->get_name() << "\", "
1511 << ((*f_iter)->is_oneway() ? "TMessageType.ONEWAY" : "TMessageType.CALL")
1512 << ", nextSeqid()));" << endl;
1513 indent(f_service_) << argsname << " args = new " << argsname << "();" << endl;
1514
1515 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1516 string arg_field_name = get_member_name((*fld_iter)->get_name());
1517 indent(f_service_) << "args." << arg_field_name << " = "
1518 << arg_field_name << ";" << endl;
1519 }
1520
1521 indent(f_service_) << "args.write(oprot);" << endl;
1522 indent(f_service_) << "oprot.writeMessageEnd();" << endl2;
1523
1524 indent(f_service_) << "await oprot.transport.flush();" << endl2;
1525
1526 if (!(*f_iter)->is_oneway()) {
1527 indent(f_service_) << "TMessage msg = iprot.readMessageBegin();" << endl;
1528 indent(f_service_) << "if (msg.type == TMessageType.EXCEPTION)";
1529 scope_up(f_service_);
1530 indent(f_service_) << "TApplicationError error = TApplicationError.read(iprot);" << endl;
1531 indent(f_service_) << "iprot.readMessageEnd();" << endl;
1532 indent(f_service_) << "throw error;" << endl;
1533 scope_down(f_service_, endl2);
1534
1535 string result_class = get_result_class_name((*f_iter)->get_name());
1536 indent(f_service_) << result_class << " result = new " << result_class << "();" << endl;
1537 indent(f_service_) << "result.read(iprot);" << endl;
1538 indent(f_service_) << "iprot.readMessageEnd();" << endl;
1539
1540 // Careful, only return _result if not a void function
1541 if (!(*f_iter)->get_returntype()->is_void()) {
1542 indent(f_service_) << "if (result." << generate_isset_check("success") << ")";
1543 scope_up(f_service_);
1544 indent(f_service_) << "return result.success;" << endl;
1545 scope_down(f_service_, endl2);
1546 }
1547
1548 t_struct* xs = (*f_iter)->get_xceptions();
1549 const std::vector<t_field*>& xceptions = xs->get_members();
1550 vector<t_field*>::const_iterator x_iter;
1551 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1552 string result_field_name = get_member_name((*x_iter)->get_name());
1553 indent(f_service_) << "if (result." << result_field_name << " != null)";
1554 scope_up(f_service_);
1555 indent(f_service_) << "throw result." << result_field_name << ";" << endl;
1556 scope_down(f_service_);
1557 }
1558
1559 // If you get here it's an exception, unless a void function
1560 if ((*f_iter)->get_returntype()->is_void()) {
1561 indent(f_service_) << "return;" << endl;
1562 } else {
1563 indent(f_service_) << "throw new TApplicationError(TApplicationErrorType.MISSING_RESULT, \""
1564 << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
1565 }
1566 }
1567
1568 scope_down(f_service_, endl2);
1569 }
1570
1571 scope_down(f_service_, endl2);
1572 }
1573
1574 /**
1575 * Generates a service server definition.
1576 *
1577 * @param tservice The service to generate a server for.
1578 */
1579 void t_dart_generator::generate_service_server(t_service* tservice) {
1580 // Generate the dispatch methods
1581 vector<t_function*> functions = tservice->get_functions();
1582 vector<t_function*>::iterator f_iter;
1583
1584 // typedef
1585 indent(f_service_) << "typedef void ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot);" << endl2;
1586
1587 // Extends stuff
1588 string extends = "";
1589 string extends_processor = "";
1590 if (tservice->get_extends() != NULL) {
1591 extends = get_ttype_class_name(tservice->get_extends());
1592 extends_processor = " extends " + extends + "Processor";
1593 }
1594
1595 // Generate the header portion
1596 string class_name = service_name_ + "Processor";
1597 export_class_to_library(get_file_name(service_name_), class_name);
1598 indent(f_service_) << "class " << class_name << extends_processor << " implements TProcessor";
1599 scope_up(f_service_);
1600
1601 indent(f_service_) << class_name << "(" << service_name_ << " iface)";
1602 if (!extends.empty()) {
1603 indent_up();
1604 f_service_ << endl;
1605 indent(f_service_) << ": super(iface)";
1606 indent_down();
1607 }
1608 scope_up(f_service_);
1609
1610 if (extends.empty()) {
1611 indent(f_service_) << "iface_ = iface;" << endl;
1612 }
1613
1614 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1615 indent(f_service_) << "PROCESS_MAP[\"" << (*f_iter)->get_name()
1616 << "\"] = " << get_member_name((*f_iter)->get_name()) << ";" << endl;
1617 }
1618 scope_down(f_service_, endl2);
1619
1620 indent(f_service_) << service_name_ << " iface_;" << endl;
1621
1622 if (extends.empty()) {
1623 indent(f_service_) << "final Map<String, ProcessFunction> PROCESS_MAP = {};" << endl;
1624 }
1625
1626 f_service_ << endl;
1627
1628 // Generate the server implementation
1629 indent(f_service_) << "bool process(TProtocol iprot, TProtocol oprot)";
1630 scope_up(f_service_);
1631 indent(f_service_) << "TMessage msg = iprot.readMessageBegin();" << endl;
1632 indent(f_service_) << "ProcessFunction fn = PROCESS_MAP[msg.name];" << endl;
1633 indent(f_service_) << "if (fn == null)";
1634 scope_up(f_service_);
1635 indent(f_service_) << "TProtocolUtil.skip(iprot, TType.STRUCT);" << endl;
1636 indent(f_service_) << "iprot.readMessageEnd();" << endl;
1637 indent(f_service_) << "TApplicationError x = new TApplicationError(TApplicationErrorType.UNKNOWN_METHOD, "
1638 "\"Invalid method name: '\"+msg.name+\"'\");" << endl;
1639 indent(f_service_) << "oprot.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));" << endl;
1640 indent(f_service_) << "x.write(oprot);" << endl;
1641 indent(f_service_) << "oprot.writeMessageEnd();" << endl;
1642 indent(f_service_) << "oprot.transport.flush();" << endl;
1643 indent(f_service_) << "return true;" << endl;
1644 scope_down(f_service_);
1645 indent(f_service_) << "fn(msg.seqid, iprot, oprot);" << endl;
1646 indent(f_service_) << "return true;" << endl;
1647 scope_down(f_service_, endl2); // process function
1648
1649 // Generate the process subfunctions
1650 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1651 generate_process_function(tservice, *f_iter);
1652 }
1653
1654 scope_down(f_service_, endl2); // class
1655 }
1656
1657 /**
1658 * Generates a struct and helpers for a function.
1659 *
1660 * @param tfunction The function
1661 */
1662 void t_dart_generator::generate_function_helpers(t_function* tfunction) {
1663 if (tfunction->is_oneway()) {
1664 return;
1665 }
1666
1667 t_struct result(program_, get_result_class_name(tfunction->get_name()));
1668 t_field success(tfunction->get_returntype(), "success", 0);
1669 if (!tfunction->get_returntype()->is_void()) {
1670 result.append(&success);
1671 }
1672
1673 t_struct* xs = tfunction->get_xceptions();
1674 const vector<t_field*>& fields = xs->get_members();
1675 vector<t_field*>::const_iterator f_iter;
1676 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1677 result.append(*f_iter);
1678 }
1679
1680 generate_dart_struct_definition(f_service_, &result, false, true);
1681 }
1682
1683 /**
1684 * Generates a process function definition.
1685 *
1686 * @param tfunction The function to write a dispatcher for
1687 */
1688 void t_dart_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
1689 (void)tservice;
1690
1691 bool await_result = (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void());
1692
1693 indent(f_service_) << get_member_name(tfunction->get_name()) << "(int seqid, TProtocol iprot, TProtocol oprot)";
1694 if (await_result) {
1695 f_service_ << " async";
1696 }
1697 scope_up(f_service_);
1698
1699 string argsname = get_args_class_name(tfunction->get_name());
1700 string resultname = get_result_class_name(tfunction->get_name());
1701
1702 indent(f_service_) << argsname << " args = new " << argsname << "();" << endl;
1703 indent(f_service_) << "args.read(iprot);" << endl;
1704 indent(f_service_) << "iprot.readMessageEnd();" << endl;
1705
1706 t_struct* xs = tfunction->get_xceptions();
1707 const std::vector<t_field*>& xceptions = xs->get_members();
1708 vector<t_field*>::const_iterator x_iter;
1709
1710 if (!tfunction->is_oneway()) {
1711 indent(f_service_) << resultname << " result = new " << resultname << "();" << endl;
1712 }
1713
1714 if (!tfunction->is_oneway() && xceptions.size() > 0) {
1715 indent(f_service_) << "try";
1716 scope_up(f_service_);
1717 }
1718
1719 // Generate the function call
1720 t_struct* arg_struct = tfunction->get_arglist();
1721 const std::vector<t_field*>& fields = arg_struct->get_members();
1722 vector<t_field*>::const_iterator f_iter;
1723
1724 f_service_ << indent();
1725 if (await_result) {
1726 f_service_ << "result.success = await ";
1727 }
1728 f_service_ << "iface_." << get_member_name(tfunction->get_name()) << "(";
1729 bool first = true;
1730 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1731 if (first) {
1732 first = false;
1733 } else {
1734 f_service_ << ", ";
1735 }
1736 f_service_ << "args." << get_member_name((*f_iter)->get_name());
1737 }
1738 f_service_ << ");" << endl;
1739
1740 if (!tfunction->is_oneway() && xceptions.size() > 0) {
1741 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1742 string result_field_name = get_member_name((*x_iter)->get_name());
1743 scope_down(f_service_, "");
1744 f_service_ << " on " << type_name((*x_iter)->get_type())
1745 << " catch(" << result_field_name << ")";
1746 scope_up(f_service_);
1747 if (!tfunction->is_oneway()) {
1748 indent(f_service_) << "result." << result_field_name << " = "
1749 << result_field_name << ";" << endl;
1750 }
1751 }
1752 scope_down(f_service_, " ");
1753 f_service_ << "catch (th)";
1754 scope_up(f_service_);
1755 indent(f_service_) << "// Internal error" << endl;
1756 indent(f_service_) << "TApplicationError x = new "
1757 "TApplicationError(TApplicationErrorType.INTERNAL_ERROR, \"Internal error processing "
1758 << tfunction->get_name() << "\");" << endl;
1759 indent(f_service_) << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name()
1760 << "\", TMessageType.EXCEPTION, seqid));" << endl;
1761 indent(f_service_) << "x.write(oprot);" << endl;
1762 indent(f_service_) << "oprot.writeMessageEnd();" << endl;
1763 indent(f_service_) << "oprot.transport.flush();" << endl;
1764 indent(f_service_) << "return;" << endl;
1765 scope_down(f_service_);
1766 }
1767
1768 if (tfunction->is_oneway()) {
1769 indent(f_service_) << "return;" << endl;
1770 } else {
1771 indent(f_service_) << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name()
1772 << "\", TMessageType.REPLY, seqid));" << endl;
1773 indent(f_service_) << "result.write(oprot);" << endl;
1774 indent(f_service_) << "oprot.writeMessageEnd();" << endl;
1775 indent(f_service_) << "oprot.transport.flush();" << endl;
1776 }
1777
1778 scope_down(f_service_, endl2);
1779 }
1780
1781 /**
1782 * Deserializes a field of any type.
1783 *
1784 * @param tfield The field
1785 * @param prefix The variable name or container for this field
1786 */
1787 void t_dart_generator::generate_deserialize_field(ostream& out, t_field* tfield, string prefix) {
1788 t_type* type = get_true_type(tfield->get_type());
1789 string field_name = get_member_name(tfield->get_name());
1790
1791 if (type->is_void()) {
1792 throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + field_name;
1793 }
1794
1795 string name = prefix + field_name;
1796
1797 if (type->is_struct() || type->is_xception()) {
1798 generate_deserialize_struct(out, (t_struct*)type, name);
1799 } else if (type->is_container()) {
1800 generate_deserialize_container(out, type, name);
1801 } else if (type->is_base_type() || type->is_enum()) {
1802
1803 indent(out) << name << " = iprot.";
1804
1805 if (type->is_base_type()) {
1806 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1807 switch (tbase) {
1808 case t_base_type::TYPE_VOID:
1809 throw "compiler error: cannot serialize void field in a struct: " + name;
1810 break;
1811 case t_base_type::TYPE_STRING:
1812 if (type->is_binary()) {
1813 out << "readBinary();";
1814 } else {
1815 out << "readString();";
1816 }
1817 break;
1818 case t_base_type::TYPE_BOOL:
1819 out << "readBool();";
1820 break;
1821 case t_base_type::TYPE_I8:
1822 out << "readByte();";
1823 break;
1824 case t_base_type::TYPE_I16:
1825 out << "readI16();";
1826 break;
1827 case t_base_type::TYPE_I32:
1828 out << "readI32();";
1829 break;
1830 case t_base_type::TYPE_I64:
1831 out << "readI64();";
1832 break;
1833 case t_base_type::TYPE_DOUBLE:
1834 out << "readDouble();";
1835 break;
1836 default:
1837 throw "compiler error: no Dart name for base type " + t_base_type::t_base_name(tbase);
1838 }
1839 } else if (type->is_enum()) {
1840 out << "readI32();";
1841 }
1842 out << endl;
1843 } else {
1844 printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
1845 field_name.c_str(),
1846 type_name(type).c_str());
1847 }
1848 }
1849
1850 /**
1851 * Generates an unserializer for a struct, invokes read()
1852 */
1853 void t_dart_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix) {
1854 indent(out) << prefix << " = new " << type_name(tstruct) << "();" << endl;
1855 indent(out) << prefix << ".read(iprot);" << endl;
1856 }
1857
1858 /**
1859 * Deserializes a container by reading its size and then iterating
1860 */
1861 void t_dart_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix) {
1862 indent(out);
1863 scope_up(out, "");
1864
1865 string obj;
1866
1867 if (ttype->is_map()) {
1868 obj = tmp("_map");
1869 } else if (ttype->is_set()) {
1870 obj = tmp("_set");
1871 } else if (ttype->is_list()) {
1872 obj = tmp("_list");
1873 }
1874
1875 // Declare variables, read header
1876 if (ttype->is_map()) {
1877 indent(out) << "TMap " << obj << " = iprot.readMapBegin();" << endl;
1878 } else if (ttype->is_set()) {
1879 indent(out) << "TSet " << obj << " = iprot.readSetBegin();" << endl;
1880 } else if (ttype->is_list()) {
1881 indent(out) << "TList " << obj << " = iprot.readListBegin();" << endl;
1882 }
1883
1884 indent(out) << prefix << " = new " << type_name(ttype) << "();" << endl;
1885
1886 // For loop iterates over elements
1887 string i = tmp("_i");
1888 indent(out) << "for (int " << i << " = 0; " << i << " < " << obj << ".length"
1889 << "; "
1890 << "++" << i << ")";
1891 scope_up(out);
1892
1893 if (ttype->is_map()) {
1894 generate_deserialize_map_element(out, (t_map*)ttype, prefix);
1895 } else if (ttype->is_set()) {
1896 generate_deserialize_set_element(out, (t_set*)ttype, prefix);
1897 } else if (ttype->is_list()) {
1898 generate_deserialize_list_element(out, (t_list*)ttype, prefix);
1899 }
1900
1901 scope_down(out);
1902
1903 // Read container end
1904 if (ttype->is_map()) {
1905 indent(out) << "iprot.readMapEnd();" << endl;
1906 } else if (ttype->is_set()) {
1907 indent(out) << "iprot.readSetEnd();" << endl;
1908 } else if (ttype->is_list()) {
1909 indent(out) << "iprot.readListEnd();" << endl;
1910 }
1911
1912 scope_down(out);
1913 }
1914
1915 /**
1916 * Generates code to deserialize a map
1917 */
1918 void t_dart_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix) {
1919 string key = tmp("_key");
1920 string val = tmp("_val");
1921 t_field fkey(tmap->get_key_type(), key);
1922 t_field fval(tmap->get_val_type(), val);
1923
1924 indent(out) << declare_field(&fkey) << endl;
1925 indent(out) << declare_field(&fval) << endl;
1926
1927 generate_deserialize_field(out, &fkey);
1928 generate_deserialize_field(out, &fval);
1929
1930 indent(out) << prefix << "[" << key << "] = " << val << ";" << endl;
1931 }
1932
1933 /**
1934 * Deserializes a set element
1935 */
1936 void t_dart_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix) {
1937 string elem = tmp("_elem");
1938 t_field felem(tset->get_elem_type(), elem);
1939
1940 indent(out) << declare_field(&felem) << endl;
1941
1942 generate_deserialize_field(out, &felem);
1943
1944 indent(out) << prefix << ".add(" << elem << ");" << endl;
1945 }
1946
1947 /**
1948 * Deserializes a list element
1949 */
1950 void t_dart_generator::generate_deserialize_list_element(ostream& out,
1951 t_list* tlist,
1952 string prefix) {
1953 string elem = tmp("_elem");
1954 t_field felem(tlist->get_elem_type(), elem);
1955
1956 indent(out) << declare_field(&felem) << endl;
1957
1958 generate_deserialize_field(out, &felem);
1959
1960 indent(out) << prefix << ".add(" << elem << ");" << endl;
1961 }
1962
1963 /**
1964 * Serializes a field of any type.
1965 *
1966 * @param tfield The field to serialize
1967 * @param prefix Name to prepend to field name
1968 */
1969 void t_dart_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix) {
1970 t_type* type = get_true_type(tfield->get_type());
1971 string field_name = get_member_name(tfield->get_name());
1972
1973 // Do nothing for void types
1974 if (type->is_void()) {
1975 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + field_name;
1976 }
1977
1978 if (type->is_struct() || type->is_xception()) {
1979 generate_serialize_struct(out, (t_struct*)type, prefix + field_name);
1980 } else if (type->is_container()) {
1981 generate_serialize_container(out, type, prefix + field_name);
1982 } else if (type->is_base_type() || type->is_enum()) {
1983
1984 string name = prefix + field_name;
1985 indent(out) << "oprot.";
1986
1987 if (type->is_base_type()) {
1988 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1989 switch (tbase) {
1990 case t_base_type::TYPE_VOID:
1991 throw "compiler error: cannot serialize void field in a struct: " + name;
1992 break;
1993 case t_base_type::TYPE_STRING:
1994 if (type->is_binary()) {
1995 out << "writeBinary(" << name << ");";
1996 } else {
1997 out << "writeString(" << name << ");";
1998 }
1999 break;
2000 case t_base_type::TYPE_BOOL:
2001 out << "writeBool(" << name << ");";
2002 break;
2003 case t_base_type::TYPE_I8:
2004 out << "writeByte(" << name << ");";
2005 break;
2006 case t_base_type::TYPE_I16:
2007 out << "writeI16(" << name << ");";
2008 break;
2009 case t_base_type::TYPE_I32:
2010 out << "writeI32(" << name << ");";
2011 break;
2012 case t_base_type::TYPE_I64:
2013 out << "writeI64(" << name << ");";
2014 break;
2015 case t_base_type::TYPE_DOUBLE:
2016 out << "writeDouble(" << name << ");";
2017 break;
2018 default:
2019 throw "compiler error: no Dart name for base type " + t_base_type::t_base_name(tbase);
2020 }
2021 } else if (type->is_enum()) {
2022 out << "writeI32(" << name << ");";
2023 }
2024 out << endl;
2025 } else {
2026 printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
2027 prefix.c_str(),
2028 field_name.c_str(),
2029 type_name(type).c_str());
2030 }
2031 }
2032
2033 /**
2034 * Serializes all the members of a struct.
2035 *
2036 * @param tstruct The struct to serialize
2037 * @param prefix String prefix to attach to all fields
2038 */
2039 void t_dart_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) {
2040 (void)tstruct;
2041 indent(out) << prefix << ".write(oprot);" << endl;
2042 }
2043
2044 /**
2045 * Serializes a container by writing its size then the elements.
2046 *
2047 * @param ttype The type of container
2048 * @param prefix String prefix for fields
2049 */
2050 void t_dart_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) {
2051 indent(out);
2052 scope_up(out, "");
2053
2054 if (ttype->is_map()) {
2055 string iter = tmp("_key");
2056 indent(out) << "oprot.writeMapBegin(new TMap(" << type_to_enum(((t_map*)ttype)->get_key_type())
2057 << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << prefix << ".length));"
2058 << endl;
2059 } else if (ttype->is_set()) {
2060 indent(out) << "oprot.writeSetBegin(new TSet(" << type_to_enum(((t_set*)ttype)->get_elem_type())
2061 << ", " << prefix << ".length));" << endl;
2062 } else if (ttype->is_list()) {
2063 indent(out) << "oprot.writeListBegin(new TList("
2064 << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix << ".length));"
2065 << endl;
2066 }
2067
2068 string iter = tmp("elem");
2069 if (ttype->is_map()) {
2070 indent(out) << "for (var " << iter << " in " << prefix << ".keys)";
2071 } else if (ttype->is_set() || ttype->is_list()) {
2072 indent(out) << "for (var " << iter << " in " << prefix << ")";
2073 }
2074
2075 scope_up(out);
2076
2077 if (ttype->is_map()) {
2078 generate_serialize_map_element(out, (t_map*)ttype, iter, prefix);
2079 } else if (ttype->is_set()) {
2080 generate_serialize_set_element(out, (t_set*)ttype, iter);
2081 } else if (ttype->is_list()) {
2082 generate_serialize_list_element(out, (t_list*)ttype, iter);
2083 }
2084
2085 scope_down(out);
2086
2087 if (ttype->is_map()) {
2088 indent(out) << "oprot.writeMapEnd();" << endl;
2089 } else if (ttype->is_set()) {
2090 indent(out) << "oprot.writeSetEnd();" << endl;
2091 } else if (ttype->is_list()) {
2092 indent(out) << "oprot.writeListEnd();" << endl;
2093 }
2094
2095 scope_down(out);
2096 }
2097
2098 /**
2099 * Serializes the members of a map.
2100 */
2101 void t_dart_generator::generate_serialize_map_element(ostream& out,
2102 t_map* tmap,
2103 string iter,
2104 string map) {
2105 t_field kfield(tmap->get_key_type(), iter);
2106 generate_serialize_field(out, &kfield, "");
2107 t_field vfield(tmap->get_val_type(), map + "[" + iter + "]");
2108 generate_serialize_field(out, &vfield, "");
2109 }
2110
2111 /**
2112 * Serializes the members of a set.
2113 */
2114 void t_dart_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) {
2115 t_field efield(tset->get_elem_type(), iter);
2116 generate_serialize_field(out, &efield, "");
2117 }
2118
2119 /**
2120 * Serializes the members of a list.
2121 */
2122 void t_dart_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) {
2123 t_field efield(tlist->get_elem_type(), iter);
2124 generate_serialize_field(out, &efield, "");
2125 }
2126
2127 /**
2128 * Returns a Dart type name
2129 *
2130 * @param ttype The type
2131 * @return Dart type name, i.e. Map<Key, Value>
2132 */
2133 string t_dart_generator::type_name(t_type* ttype) {
2134 ttype = get_true_type(ttype);
2135
2136 if (ttype->is_base_type()) {
2137 return base_type_name((t_base_type*)ttype);
2138 } else if (ttype->is_enum()) {
2139 return "int";
2140 } else if (ttype->is_map()) {
2141 t_map* tmap = (t_map*)ttype;
2142 return "Map<" + type_name(tmap->get_key_type()) + ", "
2143 + type_name(tmap->get_val_type()) + ">";
2144 } else if (ttype->is_set()) {
2145 t_set* tset = (t_set*)ttype;
2146 return "Set<" + type_name(tset->get_elem_type()) + ">";
2147 } else if (ttype->is_list()) {
2148 t_list* tlist = (t_list*)ttype;
2149 return "List<" + type_name(tlist->get_elem_type()) + ">";
2150 }
2151
2152 return get_ttype_class_name(ttype);
2153 }
2154
2155 /**
2156 * Returns the Dart type that corresponds to the thrift type.
2157 *
2158 * @param tbase The base type
2159 */
2160 string t_dart_generator::base_type_name(t_base_type* type) {
2161 t_base_type::t_base tbase = type->get_base();
2162
2163 switch (tbase) {
2164 case t_base_type::TYPE_VOID:
2165 return "void";
2166 case t_base_type::TYPE_STRING:
2167 if (type->is_binary()) {
2168 return "Uint8List";
2169 } else {
2170 return "String";
2171 }
2172 case t_base_type::TYPE_BOOL:
2173 return "bool";
2174 case t_base_type::TYPE_I8:
2175 case t_base_type::TYPE_I16:
2176 case t_base_type::TYPE_I32:
2177 case t_base_type::TYPE_I64:
2178 return "int";
2179 case t_base_type::TYPE_DOUBLE:
2180 return "double";
2181 default:
2182 throw "compiler error: no Dart name for base type " + t_base_type::t_base_name(tbase);
2183 }
2184 }
2185
2186 /**
2187 * Declares a field, which may include initialization as necessary.
2188 *
2189 * @param ttype The type
2190 */
2191 string t_dart_generator::declare_field(t_field* tfield, bool init) {
2192 string field_name = get_member_name(tfield->get_name());
2193 string result = type_name(tfield->get_type()) + " " + field_name;
2194 if (init) {
2195 t_type* ttype = get_true_type(tfield->get_type());
2196 if (ttype->is_base_type() && tfield->get_value() != NULL) {
2197 std:: ofstream dummy;
2198 result += " = " + render_const_value(dummy, field_name, ttype, tfield->get_value());
2199 } else if (ttype->is_base_type()) {
2200 t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
2201 switch (tbase) {
2202 case t_base_type::TYPE_VOID:
2203 throw "NO T_VOID CONSTRUCT";
2204 case t_base_type::TYPE_STRING:
2205 result += " = null";
2206 break;
2207 case t_base_type::TYPE_BOOL:
2208 result += " = false";
2209 break;
2210 case t_base_type::TYPE_I8:
2211 case t_base_type::TYPE_I16:
2212 case t_base_type::TYPE_I32:
2213 case t_base_type::TYPE_I64:
2214 result += " = 0";
2215 break;
2216 case t_base_type::TYPE_DOUBLE:
2217 result += " = 0.0";
2218 break;
2219 }
2220
2221 } else if (ttype->is_enum()) {
2222 result += " = 0";
2223 } else if (ttype->is_container()) {
2224 result += " = new " + type_name(ttype) + "()";
2225 } else {
2226 result += " = new " + type_name(ttype) + "()";
2227 ;
2228 }
2229 }
2230 return result + ";";
2231 }
2232
2233 /**
2234 * Renders a function signature of the form 'type name(args)'
2235 *
2236 * @param tfunction Function definition
2237 * @return String of rendered function definition
2238 */
2239 string t_dart_generator::function_signature(t_function* tfunction) {
2240 std::string arguments = argument_list(tfunction->get_arglist());
2241
2242 std::string returntype;
2243 if (tfunction->get_returntype()->is_void()) {
2244 returntype = "Future";
2245 } else {
2246 returntype = "Future<" + type_name(tfunction->get_returntype()) + ">";
2247 }
2248
2249 std::string result = returntype + " " + get_member_name(tfunction->get_name()) +
2250 "(" + arguments + ")";
2251 return result;
2252 }
2253
2254 /**
2255 * Renders a comma separated field list, with type names
2256 */
2257 string t_dart_generator::argument_list(t_struct* tstruct) {
2258 string result = "";
2259
2260 const vector<t_field*>& fields = tstruct->get_members();
2261 vector<t_field*>::const_iterator f_iter;
2262 bool first = true;
2263 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2264 if (first) {
2265 first = false;
2266 } else {
2267 result += ", ";
2268 }
2269 string field_name = get_member_name((*f_iter)->get_name());
2270 result += type_name((*f_iter)->get_type()) + " " + field_name;
2271 }
2272 return result;
2273 }
2274
2275 /**
2276 * Converts the parse type to a C++ enum string for the given type.
2277 */
2278 string t_dart_generator::type_to_enum(t_type* type) {
2279 type = get_true_type(type);
2280
2281 if (type->is_base_type()) {
2282 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2283 switch (tbase) {
2284 case t_base_type::TYPE_VOID:
2285 throw "NO T_VOID CONSTRUCT";
2286 case t_base_type::TYPE_STRING:
2287 return "TType.STRING";
2288 case t_base_type::TYPE_BOOL:
2289 return "TType.BOOL";
2290 case t_base_type::TYPE_I8:
2291 return "TType.BYTE";
2292 case t_base_type::TYPE_I16:
2293 return "TType.I16";
2294 case t_base_type::TYPE_I32:
2295 return "TType.I32";
2296 case t_base_type::TYPE_I64:
2297 return "TType.I64";
2298 case t_base_type::TYPE_DOUBLE:
2299 return "TType.DOUBLE";
2300 }
2301 } else if (type->is_enum()) {
2302 return "TType.I32";
2303 } else if (type->is_struct() || type->is_xception()) {
2304 return "TType.STRUCT";
2305 } else if (type->is_map()) {
2306 return "TType.MAP";
2307 } else if (type->is_set()) {
2308 return "TType.SET";
2309 } else if (type->is_list()) {
2310 return "TType.LIST";
2311 }
2312
2313 throw "INVALID TYPE IN type_to_enum: " + type->get_name();
2314 }
2315
2316 std::string t_dart_generator::init_value(t_field* field) {
2317 // Do not initialize optional fields
2318 if (field->get_req() == t_field::T_OPTIONAL) {
2319 return "";
2320 }
2321
2322 t_type* ttype = field->get_type();
2323
2324 // Get the actual type for a typedef
2325 if (ttype->is_typedef()) {
2326 ttype = ((t_typedef*)ttype)->get_type();
2327 }
2328
2329 // Only consider base types for default initialization
2330 if (!ttype->is_base_type()) {
2331 return "";
2332 }
2333 t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
2334
2335 // Initialize bools, ints, and doubles with sane defaults
2336 string result;
2337 switch (tbase) {
2338 case t_base_type::TYPE_BOOL:
2339 result = " = false";
2340 break;
2341 case t_base_type::TYPE_I8:
2342 case t_base_type::TYPE_I16:
2343 case t_base_type::TYPE_I32:
2344 case t_base_type::TYPE_I64:
2345 result = " = 0";
2346 break;
2347 case t_base_type::TYPE_DOUBLE:
2348 result = " = 0.0";
2349 break;
2350 case t_base_type::TYPE_VOID:
2351 case t_base_type::TYPE_STRING:
2352 result = "";
2353 break;
2354 }
2355
2356 return result;
2357 }
2358
2359 std::string t_dart_generator::get_cap_name(std::string name) {
2360 name[0] = toupper(name[0]);
2361 return name;
2362 }
2363
2364 std::string t_dart_generator::get_member_name(std::string name) {
2365 name[0] = tolower(name[0]);
2366 return name;
2367 }
2368
2369 std::string t_dart_generator::get_args_class_name(std::string name) {
2370 return name + "_args";
2371 }
2372
2373 std::string t_dart_generator::get_result_class_name(std::string name) {
2374 return name + "_result";
2375 }
2376
2377 std::string t_dart_generator::get_file_name(std::string name) {
2378 // e.g. change APIForFileIO to api_for_file_io
2379
2380 string ret;
2381 const char* tmp = name.c_str();
2382 bool is_prev_lc = true;
2383 bool is_current_lc = tmp[0] == tolower(tmp[0]);
2384 bool is_next_lc = false;
2385
2386 for (unsigned int i = 0; i < name.length(); i++) {
2387 char lc = tolower(tmp[i]);
2388
2389 if (i == name.length() - 1) {
2390 is_next_lc = false;
2391 } else {
2392 is_next_lc = (tmp[i+1] == tolower(tmp[i+1]));
2393 }
2394
2395 if (i != 0 && !is_current_lc && (is_prev_lc || is_next_lc)) {
2396 ret += "_";
2397 }
2398 ret += lc;
2399
2400 is_prev_lc = is_current_lc;
2401 is_current_lc = is_next_lc;
2402 }
2403
2404 return ret;
2405 }
2406
2407 std::string t_dart_generator::get_constants_class_name(std::string name) {
2408 // e.g. change my_great_model to MyGreatModelConstants
2409 string ret;
2410 const char* tmp = name.c_str();
2411 bool is_prev_underscore = true;
2412
2413 for (unsigned int i = 0; i < name.length(); i++) {
2414 if (tmp[i] == '_') {
2415 is_prev_underscore = true;
2416 } else {
2417 if (is_prev_underscore) {
2418 ret += toupper(tmp[i]);
2419 } else {
2420 ret += tmp[i];
2421 }
2422
2423 is_prev_underscore = false;
2424 }
2425 }
2426
2427 return ret + "Constants";
2428 }
2429
2430 string t_dart_generator::constant_name(string name) {
2431 string constant_name;
2432
2433 bool is_first = true;
2434 bool was_previous_char_upper = false;
2435 for (char character : name) {
2436 bool is_upper = isupper(character);
2437
2438 if (is_upper && !is_first && !was_previous_char_upper) {
2439 constant_name += '_';
2440 }
2441 constant_name += toupper(character);
2442
2443 is_first = false;
2444 was_previous_char_upper = is_upper;
2445 }
2446
2447 return constant_name;
2448 }
2449
2450 /**
2451 * Emits a doc comment if the provided object has a doc in Thrift
2452 */
2453 void t_dart_generator::generate_dart_doc(ostream& out, t_doc* tdoc) {
2454 if (tdoc->has_doc()) {
2455 generate_docstring_comment(out, "", "/// ", tdoc->get_doc(), "");
2456 }
2457 }
2458
2459 /**
2460 * Emits a doc comment if the provided function object has a doc in Thrift
2461 */
2462 void t_dart_generator::generate_dart_doc(ostream& out, t_function* tfunction) {
2463 if (tfunction->has_doc()) {
2464 stringstream ss;
2465 ss << tfunction->get_doc();
2466 const vector<t_field*>& fields = tfunction->get_arglist()->get_members();
2467 vector<t_field*>::const_iterator p_iter;
2468 for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) {
2469 t_field* p = *p_iter;
2470 string field_name = get_member_name(p->get_name());
2471 ss << "\n@param " << field_name;
2472 if (p->has_doc()) {
2473 ss << " " << p->get_doc();
2474 }
2475 }
2476 generate_docstring_comment(out, "", "/// ", ss.str(), "");
2477 }
2478 }
2479
2480 std::string t_dart_generator::generate_isset_check(t_field* field) {
2481 string field_name = get_member_name(field->get_name());
2482 return generate_isset_check(field_name);
2483 }
2484
2485 std::string t_dart_generator::generate_isset_check(std::string field_name) {
2486 return "is" + get_cap_name("set") + get_cap_name(field_name) + "()";
2487 }
2488
2489 void t_dart_generator::generate_isset_set(ostream& out, t_field* field) {
2490 if (!type_can_be_null(field->get_type())) {
2491 string field_name = get_member_name(field->get_name());
2492 indent(out) << "this.__isset_" << field_name << " = true;" << endl;
2493 }
2494 }
2495
2496 std::string t_dart_generator::get_ttype_class_name(t_type* ttype) {
2497 if (program_ == ttype->get_program()) {
2498 return ttype->get_name();
2499 } else {
2500 string named_import = "t_" + find_library_name(ttype->get_program());
2501 return named_import + "." + ttype->get_name();
2502 }
2503 }
2504
2505 THRIFT_REGISTER_GENERATOR(
2506 dart,
2507 "Dart",
2508 " library_name: Optional override for library name.\n"
2509 " library_prefix: Generate code that can be used within an existing library.\n"
2510 " Use a dot-separated string, e.g. \"my_parent_lib.src.gen\"\n"
2511 " pubspec_lib: Optional override for thrift lib dependency in pubspec.yaml,\n"
2512 " e.g. \"thrift: 0.x.x\". Use a pipe delimiter to separate lines,\n"
2513 " e.g. \"thrift:| git:| url: git@foo.com\"\n"
2514 )