]> git.proxmox.com Git - ceph.git/blob - ceph/src/jaegertracing/thrift/compiler/cpp/src/thrift/generate/t_netstd_generator.cc
ffe51ab0b24d80682cdfb294d3d8341c1f4e40a3
[ceph.git] / ceph / src / jaegertracing / thrift / compiler / cpp / src / thrift / generate / t_netstd_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 * Contains some contributions under the Thrift Software License.
20 * Please see doc/old-thrift-license.txt in the Thrift distribution for
21 * details.
22 */
23
24 #include <cassert>
25
26 #include <string>
27 #include <fstream>
28 #include <iostream>
29 #include <vector>
30 #include <cctype>
31
32 #include <stdlib.h>
33 #include <sys/stat.h>
34 #include <sstream>
35
36 #include "thrift/platform.h"
37 #include "thrift/generate/t_oop_generator.h"
38 #include "thrift/generate/t_netstd_generator.h"
39
40 using std::map;
41 using std::ostream;
42 using std::ostringstream;
43 using std::string;
44 using std::stringstream;
45 using std::vector;
46
47 //TODO: check for indentation
48 //TODO: Do we need seqId_ in generation?
49
50 t_netstd_generator::t_netstd_generator(t_program* program, const map<string, string>& parsed_options, const string& option_string)
51 : t_oop_generator(program)
52 {
53 (void)option_string;
54
55 union_ = false;
56 serialize_ = false;
57 wcf_ = false;
58 wcf_namespace_.clear();
59
60 map<string, string>::const_iterator iter;
61
62 for (iter = parsed_options.begin(); iter != parsed_options.end(); ++iter)
63 {
64 if (iter->first.compare("union") == 0)
65 {
66 union_ = true;
67 }
68 else if (iter->first.compare("serial") == 0)
69 {
70 serialize_ = true;
71 wcf_namespace_ = iter->second; // since there can be only one namespace
72 }
73 else if (iter->first.compare("wcf") == 0)
74 {
75 wcf_ = true;
76 wcf_namespace_ = iter->second;
77 }
78 else
79 {
80 throw "unknown option netstd:" + iter->first;
81 }
82 }
83
84 out_dir_base_ = "gen-netstd";
85 }
86
87 static string correct_function_name_for_async(string const& function_name)
88 {
89 string const async_end = "Async";
90 size_t i = function_name.find(async_end);
91 if (i != string::npos)
92 {
93 return function_name + async_end;
94 }
95
96 return function_name;
97 }
98
99 /**
100 * \brief Search and replace "_args" substring in struct name if exist (for C# class naming)
101 * \param struct_name
102 * \return Modified struct name ("Struct_args" -> "StructArgs") or original name
103 */
104 static string check_and_correct_struct_name(const string& struct_name)
105 {
106 string args_end = "_args";
107 size_t i = struct_name.find(args_end);
108 if (i != string::npos)
109 {
110 string new_struct_name = struct_name;
111 new_struct_name.replace(i, args_end.length(), "Args");
112 return new_struct_name;
113 }
114
115 string result_end = "_result";
116 size_t j = struct_name.find(result_end);
117 if (j != string::npos)
118 {
119 string new_struct_name = struct_name;
120 new_struct_name.replace(j, result_end.length(), "Result");
121 return new_struct_name;
122 }
123
124 return struct_name;
125 }
126
127 static bool field_has_default(t_field* tfield) { return tfield->get_value() != NULL; }
128
129 static bool field_is_required(t_field* tfield) { return tfield->get_req() == t_field::T_REQUIRED; }
130
131 static bool type_can_be_null(t_type* ttype)
132 {
133 while (ttype->is_typedef())
134 {
135 ttype = static_cast<t_typedef*>(ttype)->get_type();
136 }
137
138 return ttype->is_container() || ttype->is_struct() || ttype->is_xception() || ttype->is_string();
139 }
140
141 bool t_netstd_generator::is_wcf_enabled() const { return wcf_; }
142
143 bool t_netstd_generator::is_serialize_enabled() const { return serialize_; }
144
145 bool t_netstd_generator::is_union_enabled() const { return union_; }
146
147 map<string, int> t_netstd_generator::get_keywords_list() const
148 {
149 return netstd_keywords;
150 }
151
152 void t_netstd_generator::init_generator()
153 {
154 MKDIR(get_out_dir().c_str());
155
156 // for usage of csharp namespaces in thrift files (from files for csharp)
157 namespace_name_ = program_->get_namespace("netstd");
158 if (namespace_name_.empty())
159 {
160 namespace_name_ = program_->get_namespace("netstd");
161 }
162
163 string dir = namespace_name_;
164 string subdir = get_out_dir().c_str();
165 string::size_type loc;
166
167 while ((loc = dir.find(".")) != string::npos)
168 {
169 subdir = subdir + "/" + dir.substr(0, loc);
170 MKDIR(subdir.c_str());
171 dir = dir.substr(loc + 1);
172 }
173 if (dir.size() > 0)
174 {
175 subdir = subdir + "/" + dir;
176 MKDIR(subdir.c_str());
177 }
178
179 namespace_dir_ = subdir;
180 init_keywords();
181
182 while (!member_mapping_scopes.empty())
183 {
184 cleanup_member_name_mapping(member_mapping_scopes.back().scope_member);
185 }
186
187 pverbose(".NET Standard options:\n");
188 pverbose("- union ...... %s\n", (is_union_enabled() ? "ON" : "off"));
189 pverbose("- serialize .. %s\n", (is_serialize_enabled() ? "ON" : "off"));
190 pverbose("- wcf ........ %s\n", (is_wcf_enabled() ? "ON" : "off"));
191 }
192
193 string t_netstd_generator::normalize_name(string name)
194 {
195 string tmp(name);
196 transform(tmp.begin(), tmp.end(), tmp.begin(), static_cast<int(*)(int)>(tolower));
197
198 // un-conflict keywords by prefixing with "@"
199 if (netstd_keywords.find(tmp) != netstd_keywords.end())
200 {
201 return "@" + name;
202 }
203
204 // no changes necessary
205 return name;
206 }
207
208 void t_netstd_generator::init_keywords()
209 {
210 netstd_keywords.clear();
211
212 // C# keywords
213 netstd_keywords["abstract"] = 1;
214 netstd_keywords["as"] = 1;
215 netstd_keywords["base"] = 1;
216 netstd_keywords["bool"] = 1;
217 netstd_keywords["break"] = 1;
218 netstd_keywords["byte"] = 1;
219 netstd_keywords["case"] = 1;
220 netstd_keywords["catch"] = 1;
221 netstd_keywords["char"] = 1;
222 netstd_keywords["checked"] = 1;
223 netstd_keywords["class"] = 1;
224 netstd_keywords["const"] = 1;
225 netstd_keywords["continue"] = 1;
226 netstd_keywords["decimal"] = 1;
227 netstd_keywords["default"] = 1;
228 netstd_keywords["delegate"] = 1;
229 netstd_keywords["do"] = 1;
230 netstd_keywords["double"] = 1;
231 netstd_keywords["else"] = 1;
232 netstd_keywords["enum"] = 1;
233 netstd_keywords["event"] = 1;
234 netstd_keywords["explicit"] = 1;
235 netstd_keywords["extern"] = 1;
236 netstd_keywords["false"] = 1;
237 netstd_keywords["finally"] = 1;
238 netstd_keywords["fixed"] = 1;
239 netstd_keywords["float"] = 1;
240 netstd_keywords["for"] = 1;
241 netstd_keywords["foreach"] = 1;
242 netstd_keywords["goto"] = 1;
243 netstd_keywords["if"] = 1;
244 netstd_keywords["implicit"] = 1;
245 netstd_keywords["in"] = 1;
246 netstd_keywords["int"] = 1;
247 netstd_keywords["interface"] = 1;
248 netstd_keywords["internal"] = 1;
249 netstd_keywords["is"] = 1;
250 netstd_keywords["lock"] = 1;
251 netstd_keywords["long"] = 1;
252 netstd_keywords["namespace"] = 1;
253 netstd_keywords["new"] = 1;
254 netstd_keywords["null"] = 1;
255 netstd_keywords["object"] = 1;
256 netstd_keywords["operator"] = 1;
257 netstd_keywords["out"] = 1;
258 netstd_keywords["override"] = 1;
259 netstd_keywords["params"] = 1;
260 netstd_keywords["private"] = 1;
261 netstd_keywords["protected"] = 1;
262 netstd_keywords["public"] = 1;
263 netstd_keywords["readonly"] = 1;
264 netstd_keywords["ref"] = 1;
265 netstd_keywords["return"] = 1;
266 netstd_keywords["sbyte"] = 1;
267 netstd_keywords["sealed"] = 1;
268 netstd_keywords["short"] = 1;
269 netstd_keywords["sizeof"] = 1;
270 netstd_keywords["stackalloc"] = 1;
271 netstd_keywords["static"] = 1;
272 netstd_keywords["string"] = 1;
273 netstd_keywords["struct"] = 1;
274 netstd_keywords["switch"] = 1;
275 netstd_keywords["this"] = 1;
276 netstd_keywords["throw"] = 1;
277 netstd_keywords["true"] = 1;
278 netstd_keywords["try"] = 1;
279 netstd_keywords["typeof"] = 1;
280 netstd_keywords["uint"] = 1;
281 netstd_keywords["ulong"] = 1;
282 netstd_keywords["unchecked"] = 1;
283 netstd_keywords["unsafe"] = 1;
284 netstd_keywords["ushort"] = 1;
285 netstd_keywords["using"] = 1;
286 netstd_keywords["virtual"] = 1;
287 netstd_keywords["void"] = 1;
288 netstd_keywords["volatile"] = 1;
289 netstd_keywords["while"] = 1;
290
291 // C# contextual keywords
292 netstd_keywords["add"] = 1;
293 netstd_keywords["alias"] = 1;
294 netstd_keywords["ascending"] = 1;
295 netstd_keywords["async"] = 1;
296 netstd_keywords["await"] = 1;
297 netstd_keywords["descending"] = 1;
298 netstd_keywords["dynamic"] = 1;
299 netstd_keywords["from"] = 1;
300 netstd_keywords["get"] = 1;
301 netstd_keywords["global"] = 1;
302 netstd_keywords["group"] = 1;
303 netstd_keywords["into"] = 1;
304 netstd_keywords["join"] = 1;
305 netstd_keywords["let"] = 1;
306 netstd_keywords["orderby"] = 1;
307 netstd_keywords["partial"] = 1;
308 netstd_keywords["remove"] = 1;
309 netstd_keywords["select"] = 1;
310 netstd_keywords["set"] = 1;
311 netstd_keywords["value"] = 1;
312 netstd_keywords["var"] = 1;
313 netstd_keywords["where"] = 1;
314 netstd_keywords["yield"] = 1;
315
316 netstd_keywords["when"] = 1;
317 }
318
319 void t_netstd_generator::start_netstd_namespace(ostream& out)
320 {
321 if (!namespace_name_.empty())
322 {
323 out << "namespace " << namespace_name_ << endl;
324 scope_up(out);
325 }
326 }
327
328 void t_netstd_generator::end_netstd_namespace(ostream& out)
329 {
330 if (!namespace_name_.empty())
331 {
332 scope_down(out);
333 }
334 }
335
336 string t_netstd_generator::netstd_type_usings() const
337 {
338 string namespaces =
339 "using System;\n"
340 "using System.Collections;\n"
341 "using System.Collections.Generic;\n"
342 "using System.Text;\n"
343 "using System.IO;\n"
344 "using System.Threading;\n"
345 "using System.Threading.Tasks;\n"
346 "using Thrift;\n"
347 "using Thrift.Collections;\n";
348
349 if (is_wcf_enabled())
350 {
351 namespaces += "using System.ServiceModel;\n";
352 namespaces += "using System.Runtime.Serialization;\n";
353 }
354
355 return namespaces + endl;
356 }
357
358 string t_netstd_generator::netstd_thrift_usings() const
359 {
360 string namespaces =
361 "using Thrift.Protocol;\n"
362 "using Thrift.Protocol.Entities;\n"
363 "using Thrift.Protocol.Utilities;\n"
364 "using Thrift.Transport;\n"
365 "using Thrift.Transport.Client;\n"
366 "using Thrift.Transport.Server;\n"
367 "using Thrift.Processor;\n";
368
369 return namespaces + endl;
370 }
371
372 void t_netstd_generator::close_generator()
373 {
374 }
375
376 void t_netstd_generator::generate_typedef(t_typedef* ttypedef)
377 {
378 (void)ttypedef;
379 }
380
381 void t_netstd_generator::generate_enum(t_enum* tenum)
382 {
383 int ic = indent_count();
384 string f_enum_name = namespace_dir_ + "/" + tenum->get_name() + ".cs";
385
386 ofstream_with_content_based_conditional_update f_enum;
387 f_enum.open(f_enum_name.c_str());
388
389 generate_enum(f_enum, tenum);
390
391 f_enum.close();
392 indent_validate(ic, "generate_enum");
393 }
394
395 void t_netstd_generator::generate_enum(ostream& out, t_enum* tenum)
396 {
397 out << autogen_comment() << endl;
398
399 start_netstd_namespace(out);
400 generate_netstd_doc(out, tenum);
401
402 out << indent() << "public enum " << tenum->get_name() << endl;
403 scope_up(out);
404
405 vector<t_enum_value*> constants = tenum->get_constants();
406 vector<t_enum_value*>::iterator c_iter;
407
408 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter)
409 {
410 generate_netstd_doc(out, *c_iter);
411 int value = (*c_iter)->get_value();
412 out << indent() << (*c_iter)->get_name() << " = " << value << "," << endl;
413 }
414
415 scope_down(out);
416 end_netstd_namespace(out);
417 }
418
419 void t_netstd_generator::generate_consts(vector<t_const*> consts)
420 {
421 if (consts.empty())
422 {
423 return;
424 }
425
426 string f_consts_name = namespace_dir_ + '/' + program_name_ + ".Constants.cs";
427 ofstream_with_content_based_conditional_update f_consts;
428 f_consts.open(f_consts_name.c_str());
429
430 generate_consts(f_consts, consts);
431
432 f_consts.close();
433 }
434
435 void t_netstd_generator::generate_consts(ostream& out, vector<t_const*> consts)
436 {
437 if (consts.empty())
438 {
439 return;
440 }
441
442 out << autogen_comment() << netstd_type_usings() << endl;
443
444 start_netstd_namespace(out);
445
446 out << indent() << "public static class " << make_valid_csharp_identifier(program_name_) << "Constants" << endl;
447
448 scope_up(out);
449
450 vector<t_const*>::iterator c_iter;
451 bool need_static_constructor = false;
452 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter)
453 {
454 generate_netstd_doc(out, *c_iter);
455 if (print_const_value(out, (*c_iter)->get_name(), (*c_iter)->get_type(), (*c_iter)->get_value(), false))
456 {
457 need_static_constructor = true;
458 }
459 }
460
461 if (need_static_constructor)
462 {
463 print_const_constructor(out, consts);
464 }
465
466 scope_down(out);
467 end_netstd_namespace(out);
468 }
469
470 void t_netstd_generator::print_const_def_value(ostream& out, string name, t_type* type, t_const_value* value)
471 {
472 if (type->is_struct() || type->is_xception())
473 {
474 const vector<t_field*>& fields = static_cast<t_struct*>(type)->get_members();
475 const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
476 vector<t_field*>::const_iterator f_iter;
477 map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
478 prepare_member_name_mapping(static_cast<t_struct*>(type));
479
480 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter)
481 {
482 t_field* field = NULL;
483
484 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
485 {
486 if ((*f_iter)->get_name() == v_iter->first->get_string())
487 {
488 field = *f_iter;
489 }
490 }
491
492 if (field == NULL)
493 {
494 throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
495 }
496
497 t_type* field_type = field->get_type();
498
499 string val = render_const_value(out, name, field_type, v_iter->second);
500 out << indent() << name << "." << prop_name(field) << " = " << val << ";" << endl;
501 }
502
503 cleanup_member_name_mapping(static_cast<t_struct*>(type));
504 }
505 else if (type->is_map())
506 {
507 t_type* ktype = static_cast<t_map*>(type)->get_key_type();
508 t_type* vtype = static_cast<t_map*>(type)->get_val_type();
509 const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
510 map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
511 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter)
512 {
513 string key = render_const_value(out, name, ktype, v_iter->first);
514 string val = render_const_value(out, name, vtype, v_iter->second);
515 out << indent() << name << "[" << key << "]" << " = " << val << ";" << endl;
516 }
517 }
518 else if (type->is_list() || type->is_set())
519 {
520 t_type* etype;
521 if (type->is_list())
522 {
523 etype = static_cast<t_list*>(type)->get_elem_type();
524 }
525 else
526 {
527 etype = static_cast<t_set*>(type)->get_elem_type();
528 }
529
530 const vector<t_const_value*>& val = value->get_list();
531 vector<t_const_value*>::const_iterator v_iter;
532 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter)
533 {
534 string val = render_const_value(out, name, etype, *v_iter);
535 out << indent() << name << ".Add(" << val << ");" << endl;
536 }
537 }
538 }
539
540 void t_netstd_generator::print_const_constructor(ostream& out, vector<t_const*> consts)
541 {
542 out << indent() << "static " << make_valid_csharp_identifier(program_name_).c_str() << "Constants()" << endl;
543 scope_up(out);
544
545 vector<t_const*>::iterator c_iter;
546 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter)
547 {
548 string name = (*c_iter)->get_name();
549 t_type* type = (*c_iter)->get_type();
550 t_const_value* value = (*c_iter)->get_value();
551
552 print_const_def_value(out, name, type, value);
553 }
554 scope_down(out);
555 }
556
557 bool t_netstd_generator::print_const_value(ostream& out, string name, t_type* type, t_const_value* value, bool in_static, bool defval, bool needtype)
558 {
559 out << indent();
560 bool need_static_construction = !in_static;
561 while (type->is_typedef())
562 {
563 type = static_cast<t_typedef*>(type)->get_type();
564 }
565
566 if (!defval || needtype)
567 {
568 out << (in_static ? "" : type->is_base_type() ? "public const " : "public static ") << type_name(type) << " ";
569 }
570
571 if (type->is_base_type())
572 {
573 string v2 = render_const_value(out, name, type, value);
574 out << normalize_name(name) << " = " << v2 << ";" << endl;
575 need_static_construction = false;
576 }
577 else if (type->is_enum())
578 {
579 out << name << " = " << type_name(type) << "." << value->get_identifier_name() << ";" << endl;
580 need_static_construction = false;
581 }
582 else if (type->is_struct() || type->is_xception())
583 {
584 out << name << " = new " << type_name(type) << "();" << endl;
585 }
586 else if (type->is_map())
587 {
588 out << name << " = new " << type_name(type) << "();" << endl;
589 }
590 else if (type->is_list() || type->is_set())
591 {
592 out << name << " = new " << type_name(type) << "();" << endl;
593 }
594
595 if (defval && !type->is_base_type() && !type->is_enum())
596 {
597 print_const_def_value(out, name, type, value);
598 }
599
600 return need_static_construction;
601 }
602
603 string t_netstd_generator::render_const_value(ostream& out, string name, t_type* type, t_const_value* value)
604 {
605 (void)name;
606 ostringstream render;
607
608 if (type->is_base_type())
609 {
610 t_base_type::t_base tbase = static_cast<t_base_type*>(type)->get_base();
611 switch (tbase)
612 {
613 case t_base_type::TYPE_STRING:
614 render << '"' << get_escaped_string(value) << '"';
615 break;
616 case t_base_type::TYPE_BOOL:
617 render << ((value->get_integer() > 0) ? "true" : "false");
618 break;
619 case t_base_type::TYPE_I8:
620 case t_base_type::TYPE_I16:
621 case t_base_type::TYPE_I32:
622 case t_base_type::TYPE_I64:
623 render << value->get_integer();
624 break;
625 case t_base_type::TYPE_DOUBLE:
626 if (value->get_type() == t_const_value::CV_INTEGER)
627 {
628 render << value->get_integer();
629 }
630 else
631 {
632 render << value->get_double();
633 }
634 break;
635 default:
636 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
637 }
638 }
639 else if (type->is_enum())
640 {
641 render << type->get_name() << "." << value->get_identifier_name();
642 }
643 else
644 {
645 string t = tmp("tmp");
646 print_const_value(out, t, type, value, true, true, true);
647 render << t;
648 }
649
650 return render.str();
651 }
652
653 void t_netstd_generator::generate_struct(t_struct* tstruct)
654 {
655 if (is_union_enabled() && tstruct->is_union())
656 {
657 generate_netstd_union(tstruct);
658 }
659 else
660 {
661 generate_netstd_struct(tstruct, false);
662 }
663 }
664
665 void t_netstd_generator::generate_xception(t_struct* txception)
666 {
667 generate_netstd_struct(txception, true);
668 }
669
670 void t_netstd_generator::generate_netstd_struct(t_struct* tstruct, bool is_exception)
671 {
672 int ic = indent_count();
673
674 string f_struct_name = namespace_dir_ + "/" + (tstruct->get_name()) + ".cs";
675 ofstream_with_content_based_conditional_update f_struct;
676
677 f_struct.open(f_struct_name.c_str());
678
679 f_struct << autogen_comment() << netstd_type_usings() << netstd_thrift_usings() << endl;
680
681 generate_netstd_struct_definition(f_struct, tstruct, is_exception);
682
683 f_struct.close();
684
685 indent_validate(ic, "generate_netstd_struct");
686 }
687
688 void t_netstd_generator::generate_netstd_struct_definition(ostream& out, t_struct* tstruct, bool is_exception, bool in_class, bool is_result)
689 {
690 if (!in_class)
691 {
692 start_netstd_namespace(out);
693 }
694
695 out << endl;
696
697 generate_netstd_doc(out, tstruct);
698 prepare_member_name_mapping(tstruct);
699
700 if ((is_serialize_enabled() || is_wcf_enabled()) && !is_exception)
701 {
702 out << indent() << "[DataContract(Namespace=\"" << wcf_namespace_ << "\")]" << endl;
703 }
704
705 bool is_final = tstruct->annotations_.find("final") != tstruct->annotations_.end();
706
707 string sharp_struct_name = check_and_correct_struct_name(normalize_name(tstruct->get_name()));
708
709 out << indent() << "public " << (is_final ? "sealed " : "") << "partial class " << sharp_struct_name << " : ";
710
711 if (is_exception)
712 {
713 out << "TException, ";
714 }
715
716 out << "TBase" << endl
717 << indent() << "{" << endl;
718 indent_up();
719
720 const vector<t_field*>& members = tstruct->get_members();
721 vector<t_field*>::const_iterator m_iter;
722
723 // make private members with public Properties
724 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter)
725 {
726 // if the field is required, then we use auto-properties
727 if (!field_is_required((*m_iter)))
728 {
729 out << indent() << "private " << declare_field(*m_iter, false, "_") << endl;
730 }
731 }
732 out << endl;
733
734 bool has_non_required_fields = false;
735 bool has_required_fields = false;
736 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter)
737 {
738 generate_netstd_doc(out, *m_iter);
739 generate_property(out, *m_iter, true, true);
740 bool is_required = field_is_required((*m_iter));
741 if (is_required)
742 {
743 has_required_fields = true;
744 }
745 else
746 {
747 has_non_required_fields = true;
748 }
749 }
750
751 bool generate_isset = has_non_required_fields;
752 if (generate_isset)
753 {
754 out << endl;
755 if (is_serialize_enabled() || is_wcf_enabled())
756 {
757 out << indent() << "[DataMember(Order = 1)]" << endl;
758 }
759 out << indent() << "public Isset __isset;" << endl;
760 if (is_serialize_enabled() || is_wcf_enabled())
761 {
762 out << indent() << "[DataContract]" << endl;
763 }
764
765 out << indent() << "public struct Isset" << endl
766 << indent() << "{" << endl;
767 indent_up();
768
769 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter)
770 {
771 bool is_required = field_is_required((*m_iter));
772 // if it is required, don't need Isset for that variable
773 // if it is not required, if it has a default value, we need to generate Isset
774 if (!is_required)
775 {
776 if (is_serialize_enabled() || is_wcf_enabled())
777 {
778 out << indent() << "[DataMember]" << endl;
779 }
780 out << indent() << "public bool " << normalize_name((*m_iter)->get_name()) << ";" << endl;
781 }
782 }
783
784 indent_down();
785 out << indent() << "}" << endl << endl;
786
787 if (generate_isset && (is_serialize_enabled() || is_wcf_enabled()))
788 {
789 out << indent() << "#region XmlSerializer support" << endl << endl;
790
791 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter)
792 {
793 bool is_required = field_is_required(*m_iter);
794 // if it is required, don't need Isset for that variable
795 // if it is not required, if it has a default value, we need to generate Isset
796 if (!is_required)
797 {
798 out << indent() << "public bool ShouldSerialize" << prop_name(*m_iter) << "()" << endl
799 << indent() << "{" << endl;
800 indent_up();
801 out << indent() << "return __isset." << normalize_name((*m_iter)->get_name()) << ";" << endl;
802 indent_down();
803 out << indent() << "}" << endl << endl;
804 }
805 }
806
807 out << indent() << "#endregion XmlSerializer support" << endl << endl;
808 }
809 }
810
811 // We always want a default, no argument constructor for Reading
812 out << indent() << "public " << sharp_struct_name << "()" << endl
813 << indent() << "{" << endl;
814 indent_up();
815
816 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter)
817 {
818 t_type* t = (*m_iter)->get_type();
819 while (t->is_typedef())
820 {
821 t = static_cast<t_typedef*>(t)->get_type();
822 }
823 if ((*m_iter)->get_value() != NULL)
824 {
825 if (field_is_required((*m_iter)))
826 {
827 print_const_value(out, "this." + prop_name(*m_iter), t, (*m_iter)->get_value(), true, true);
828 }
829 else
830 {
831 print_const_value(out, "this._" + (*m_iter)->get_name(), t, (*m_iter)->get_value(), true, true);
832 // Optionals with defaults are marked set
833 out << indent() << "this.__isset." << normalize_name((*m_iter)->get_name()) << " = true;" << endl;
834 }
835 }
836 }
837 indent_down();
838 out << indent() << "}" << endl << endl;
839
840 if (has_required_fields)
841 {
842 out << indent() << "public " << sharp_struct_name << "(";
843 bool first = true;
844 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter)
845 {
846 if (field_is_required(*m_iter))
847 {
848 if (first)
849 {
850 first = false;
851 }
852 else
853 {
854 out << ", ";
855 }
856 out << type_name((*m_iter)->get_type()) << " " << (*m_iter)->get_name();
857 }
858 }
859 out << ") : this()" << endl
860 << indent() << "{" << endl;
861 indent_up();
862
863 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter)
864 {
865 if (field_is_required(*m_iter))
866 {
867 out << indent() << "this." << prop_name(*m_iter) << " = " << (*m_iter)->get_name() << ";" << endl;
868 }
869 }
870
871 indent_down();
872 out << indent() << "}" << endl << endl;
873 }
874
875 generate_netstd_struct_reader(out, tstruct);
876 if (is_result)
877 {
878 generate_netstd_struct_result_writer(out, tstruct);
879 }
880 else
881 {
882 generate_netstd_struct_writer(out, tstruct);
883 }
884 generate_netstd_struct_equals(out, tstruct);
885 generate_netstd_struct_hashcode(out, tstruct);
886 generate_netstd_struct_tostring(out, tstruct);
887
888 indent_down();
889 out << indent() << "}" << endl << endl;
890
891 // generate a corresponding WCF fault to wrap the exception
892 if ((is_serialize_enabled() || is_wcf_enabled()) && is_exception)
893 {
894 generate_netstd_wcffault(out, tstruct);
895 }
896
897 cleanup_member_name_mapping(tstruct);
898 if (!in_class)
899 {
900 end_netstd_namespace(out);
901 }
902 }
903
904 void t_netstd_generator::generate_netstd_wcffault(ostream& out, t_struct* tstruct)
905 {
906 out << endl;
907 out << indent() << "[DataContract]" << endl;
908
909 bool is_final = tstruct->annotations_.find("final") != tstruct->annotations_.end();
910
911 out << indent() << "public " << (is_final ? "sealed " : "") << "partial class " << tstruct->get_name() << "Fault" << endl
912 << indent() << "{" << endl;
913 indent_up();
914
915 const vector<t_field*>& members = tstruct->get_members();
916 vector<t_field*>::const_iterator m_iter;
917
918 // make private members with public Properties
919 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter)
920 {
921 // if the field is required, then we use auto-properties
922 if (!field_is_required((*m_iter)))
923 {
924 out << indent() << "private " << declare_field(*m_iter, false, "_") << endl;
925 }
926 }
927 out << endl;
928
929 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter)
930 {
931 generate_property(out, *m_iter, true, false);
932 }
933
934 indent_down();
935 out << indent() << "}" << endl << endl;
936 }
937
938 void t_netstd_generator::generate_netstd_struct_reader(ostream& out, t_struct* tstruct)
939 {
940 out << indent() << "public async Task ReadAsync(TProtocol iprot, CancellationToken cancellationToken)" << endl
941 << indent() << "{" << endl;
942 indent_up();
943 out << indent() << "iprot.IncrementRecursionDepth();" << endl
944 << indent() << "try" << endl
945 << indent() << "{" << endl;
946 indent_up();
947
948 const vector<t_field*>& fields = tstruct->get_members();
949 vector<t_field*>::const_iterator f_iter;
950
951 // Required variables aren't in __isset, so we need tmp vars to check them
952 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
953 {
954 if (field_is_required(*f_iter))
955 {
956 out << indent() << "bool isset_" << (*f_iter)->get_name() << " = false;" << endl;
957 }
958 }
959
960 out << indent() << "TField field;" << endl
961 << indent() << "await iprot.ReadStructBeginAsync(cancellationToken);" << endl
962 << indent() << "while (true)" << endl
963 << indent() << "{" << endl;
964 indent_up();
965 out << indent() << "field = await iprot.ReadFieldBeginAsync(cancellationToken);" << endl
966 << indent() << "if (field.Type == TType.Stop)" << endl
967 << indent() << "{" << endl;
968 indent_up();
969 out << indent() << "break;" << endl;
970 indent_down();
971 out << indent() << "}" << endl << endl
972 << indent() << "switch (field.ID)" << endl
973 << indent() << "{" << endl;
974 indent_up();
975
976 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
977 {
978 bool is_required = field_is_required(*f_iter);
979 out << indent() << "case " << (*f_iter)->get_key() << ":" << endl;
980 indent_up();
981 out << indent() << "if (field.Type == " << type_to_enum((*f_iter)->get_type()) << ")" << endl
982 << indent() << "{" << endl;
983 indent_up();
984
985 generate_deserialize_field(out, *f_iter);
986 if (is_required)
987 {
988 out << indent() << "isset_" << (*f_iter)->get_name() << " = true;" << endl;
989 }
990
991 indent_down();
992 out << indent() << "}" << endl
993 << indent() << "else" << endl
994 << indent() << "{" << endl;
995 indent_up();
996 out << indent() << "await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);" << endl;
997 indent_down();
998 out << indent() << "}" << endl
999 << indent() << "break;" << endl;
1000 indent_down();
1001 }
1002
1003 out << indent() << "default: " << endl;
1004 indent_up();
1005 out << indent() << "await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);" << endl
1006 << indent() << "break;" << endl;
1007 indent_down();
1008 indent_down();
1009 out << indent() << "}" << endl
1010 << endl
1011 << indent() << "await iprot.ReadFieldEndAsync(cancellationToken);" << endl;
1012 indent_down();
1013 out << indent() << "}" << endl
1014 << endl
1015 << indent() << "await iprot.ReadStructEndAsync(cancellationToken);" << endl;
1016
1017 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
1018 {
1019 if (field_is_required((*f_iter)))
1020 {
1021 out << indent() << "if (!isset_" << (*f_iter)->get_name() << ")" << endl
1022 << indent() << "{" << endl;
1023 indent_up();
1024 out << indent() << "throw new TProtocolException(TProtocolException.INVALID_DATA);" << endl;
1025 indent_down();
1026 out << indent() << "}" << endl;
1027 }
1028 }
1029
1030 indent_down();
1031 out << indent() << "}" << endl;
1032 out << indent() << "finally" << endl
1033 << indent() << "{" << endl;
1034 indent_up();
1035 out << indent() << "iprot.DecrementRecursionDepth();" << endl;
1036 indent_down();
1037 out << indent() << "}" << endl;
1038 indent_down();
1039 out << indent() << "}" << endl << endl;
1040 }
1041
1042 void t_netstd_generator::generate_netstd_struct_writer(ostream& out, t_struct* tstruct)
1043 {
1044 out << indent() << "public async Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken)" << endl
1045 << indent() << "{" << endl;
1046 indent_up();
1047
1048 out << indent() << "oprot.IncrementRecursionDepth();" << endl
1049 << indent() << "try" << endl
1050 << indent() << "{" << endl;
1051 indent_up();
1052
1053 string name = tstruct->get_name();
1054 const vector<t_field*>& fields = tstruct->get_sorted_members();
1055 vector<t_field*>::const_iterator f_iter;
1056
1057 out << indent() << "var struc = new TStruct(\"" << name << "\");" << endl
1058 << indent() << "await oprot.WriteStructBeginAsync(struc, cancellationToken);" << endl;
1059
1060 if (fields.size() > 0)
1061 {
1062 out << indent() << "var field = new TField();" << endl;
1063 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
1064 {
1065 bool is_required = field_is_required(*f_iter);
1066 if (!is_required)
1067 {
1068 bool null_allowed = type_can_be_null((*f_iter)->get_type());
1069 if (null_allowed)
1070 {
1071 out << indent() << "if (" << prop_name(*f_iter) << " != null && __isset." << normalize_name((*f_iter)->get_name()) << ")" << endl
1072 << indent() << "{" << endl;
1073 indent_up();
1074 }
1075 else
1076 {
1077 out << indent() << "if (__isset." << normalize_name((*f_iter)->get_name()) << ")" << endl
1078 << indent() << "{" << endl;
1079 indent_up();
1080 }
1081 }
1082 out << indent() << "field.Name = \"" << (*f_iter)->get_name() << "\";" << endl
1083 << indent() << "field.Type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl
1084 << indent() << "field.ID = " << (*f_iter)->get_key() << ";" << endl
1085 << indent() << "await oprot.WriteFieldBeginAsync(field, cancellationToken);" << endl;
1086
1087 generate_serialize_field(out, *f_iter);
1088
1089 out << indent() << "await oprot.WriteFieldEndAsync(cancellationToken);" << endl;
1090 if (!is_required)
1091 {
1092 indent_down();
1093 out << indent() << "}" << endl;
1094 }
1095 }
1096 }
1097
1098 out << indent() << "await oprot.WriteFieldStopAsync(cancellationToken);" << endl
1099 << indent() << "await oprot.WriteStructEndAsync(cancellationToken);" << endl;
1100 indent_down();
1101 out << indent() << "}" << endl
1102 << indent() << "finally" << endl
1103 << indent() << "{" << endl;
1104 indent_up();
1105 out << indent() << "oprot.DecrementRecursionDepth();" << endl;
1106 indent_down();
1107 out << indent() << "}" << endl;
1108 indent_down();
1109 out << indent() << "}" << endl << endl;
1110 }
1111
1112 void t_netstd_generator::generate_netstd_struct_result_writer(ostream& out, t_struct* tstruct)
1113 {
1114 out << indent() << "public async Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken)" << endl
1115 << indent() << "{" << endl;
1116 indent_up();
1117
1118 out << indent() << "oprot.IncrementRecursionDepth();" << endl
1119 << indent() << "try" << endl
1120 << indent() << "{" << endl;
1121 indent_up();
1122
1123 string name = tstruct->get_name();
1124 const vector<t_field*>& fields = tstruct->get_sorted_members();
1125 vector<t_field*>::const_iterator f_iter;
1126
1127 out << indent() << "var struc = new TStruct(\"" << name << "\");" << endl
1128 << indent() << "await oprot.WriteStructBeginAsync(struc, cancellationToken);" << endl;
1129
1130 if (fields.size() > 0)
1131 {
1132 out << indent() << "var field = new TField();" << endl;
1133 bool first = true;
1134 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
1135 {
1136 if (first)
1137 {
1138 first = false;
1139 out << endl << indent() << "if";
1140 }
1141 else
1142 {
1143 out << indent() << "else if";
1144 }
1145
1146 out << "(this.__isset." << normalize_name((*f_iter)->get_name()) << ")" << endl
1147 << indent() << "{" << endl;
1148 indent_up();
1149
1150 bool null_allowed = type_can_be_null((*f_iter)->get_type());
1151 if (null_allowed)
1152 {
1153 out << indent() << "if (" << prop_name(*f_iter) << " != null)" << endl
1154 << indent() << "{" << endl;
1155 indent_up();
1156 }
1157
1158 out << indent() << "field.Name = \"" << prop_name(*f_iter) << "\";" << endl
1159 << indent() << "field.Type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl
1160 << indent() << "field.ID = " << (*f_iter)->get_key() << ";" << endl
1161 << indent() << "await oprot.WriteFieldBeginAsync(field, cancellationToken);" << endl;
1162
1163 generate_serialize_field(out, *f_iter);
1164
1165 out << indent() << "await oprot.WriteFieldEndAsync(cancellationToken);" << endl;
1166
1167 if (null_allowed)
1168 {
1169 indent_down();
1170 out << indent() << "}" << endl;
1171 }
1172
1173 indent_down();
1174 out << indent() << "}" << endl;
1175 }
1176 }
1177
1178 out << indent() << "await oprot.WriteFieldStopAsync(cancellationToken);" << endl
1179 << indent() << "await oprot.WriteStructEndAsync(cancellationToken);" << endl;
1180 indent_down();
1181 out << indent() << "}" << endl
1182 << indent() << "finally" << endl
1183 << indent() << "{" << endl;
1184 indent_up();
1185 out << indent() << "oprot.DecrementRecursionDepth();" << endl;
1186 indent_down();
1187 out << indent() << "}" << endl;
1188 indent_down();
1189 out << indent() << "}" << endl << endl;
1190 }
1191
1192 void t_netstd_generator::generate_netstd_struct_tostring(ostream& out, t_struct* tstruct)
1193 {
1194 out << indent() << "public override string ToString()" << endl
1195 << indent() << "{" << endl;
1196 indent_up();
1197 out << indent() << "var sb = new StringBuilder(\"" << tstruct->get_name() << "(\");" << endl;
1198
1199 const vector<t_field*>& fields = tstruct->get_members();
1200 vector<t_field*>::const_iterator f_iter;
1201
1202 bool useFirstFlag = false;
1203 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
1204 {
1205 if (!field_is_required((*f_iter)))
1206 {
1207 out << indent() << "bool __first = true;" << endl;
1208 useFirstFlag = true;
1209 }
1210 break;
1211 }
1212
1213 bool had_required = false; // set to true after first required field has been processed
1214
1215 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
1216 {
1217 bool is_required = field_is_required((*f_iter));
1218 if (!is_required)
1219 {
1220 bool null_allowed = type_can_be_null((*f_iter)->get_type());
1221 if (null_allowed)
1222 {
1223 out << indent() << "if (" << prop_name((*f_iter)) << " != null && __isset." << normalize_name((*f_iter)->get_name()) << ")" << endl
1224 << indent() << "{" << endl;
1225 indent_up();
1226 }
1227 else
1228 {
1229 out << indent() << "if (__isset." << normalize_name((*f_iter)->get_name()) << ")" << endl
1230 << indent() << "{" << endl;
1231 indent_up();
1232 }
1233 }
1234
1235 if (useFirstFlag && (!had_required))
1236 {
1237 out << indent() << "if(!__first) { sb.Append(\", \"); }" << endl;
1238 if (!is_required)
1239 {
1240 out << indent() << "__first = false;" << endl;
1241 }
1242 out << indent() << "sb.Append(\"" << prop_name(*f_iter) << ": \");" << endl;
1243 }
1244 else
1245 {
1246 out << indent() << "sb.Append(\", " << prop_name(*f_iter) << ": \");" << endl;
1247 }
1248
1249 t_type* ttype = (*f_iter)->get_type();
1250 if (ttype->is_xception() || ttype->is_struct())
1251 {
1252 out << indent() << "sb.Append(" << prop_name(*f_iter) << "== null ? \"<null>\" : " << prop_name(*f_iter) << ".ToString());" << endl;
1253 }
1254 else
1255 {
1256 out << indent() << "sb.Append(" << prop_name(*f_iter) << ");" << endl;
1257 }
1258
1259 if (!is_required)
1260 {
1261 indent_down();
1262 out << indent() << "}" << endl;
1263 }
1264 else
1265 {
1266 had_required = true; // now __first must be false, so we don't need to check it anymore
1267 }
1268 }
1269
1270 out << indent() << "sb.Append(\")\");" << endl
1271 << indent() << "return sb.ToString();" << endl;
1272 indent_down();
1273 out << indent() << "}" << endl;
1274 }
1275
1276 void t_netstd_generator::generate_netstd_union(t_struct* tunion)
1277 {
1278 int ic = indent_count();
1279
1280 string f_union_name = namespace_dir_ + "/" + (tunion->get_name()) + ".cs";
1281 ofstream_with_content_based_conditional_update f_union;
1282
1283 f_union.open(f_union_name.c_str());
1284
1285 f_union << autogen_comment() << netstd_type_usings() << netstd_thrift_usings() << endl;
1286
1287 generate_netstd_union_definition(f_union, tunion);
1288
1289 f_union.close();
1290
1291 indent_validate(ic, "generate_netstd_union.");
1292 }
1293
1294 void t_netstd_generator::generate_netstd_union_definition(ostream& out, t_struct* tunion)
1295 {
1296 // Let's define the class first
1297 start_netstd_namespace(out);
1298
1299 out << indent() << "public abstract partial class " << tunion->get_name() << " : TUnionBase" << endl
1300 << indent() << "{" << endl;
1301 indent_up();
1302
1303 out << indent() << "public abstract Task WriteAsync(TProtocol tProtocol, CancellationToken cancellationToken);" << endl
1304 << indent() << "public readonly int Isset;" << endl
1305 << indent() << "public abstract object Data { get; }" << endl
1306 << indent() << "protected " << tunion->get_name() << "(int isset)" << endl
1307 << indent() << "{" << endl;
1308 indent_up();
1309 out << indent() << "Isset = isset;" << endl;
1310 indent_down();
1311 out << indent() << "}" << endl << endl;
1312
1313 out << indent() << "public class ___undefined : " << tunion->get_name() << endl
1314 << indent() << "{" << endl;
1315 indent_up();
1316
1317 out << indent() << "public override object Data { get { return null; } }" << endl
1318 << indent() << "public ___undefined() : base(0) {}" << endl << endl;
1319
1320 out << indent() << "public override Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken)" << endl
1321 << indent() << "{" << endl;
1322 indent_up();
1323 out << indent() << "throw new TProtocolException( TProtocolException.INVALID_DATA, \"Cannot persist an union type which is not set.\");" << endl;
1324 indent_down();
1325 out << indent() << "}" << endl << endl;
1326 indent_down();
1327 out << indent() << "}" << endl << endl;
1328
1329 const vector<t_field*>& fields = tunion->get_members();
1330 vector<t_field*>::const_iterator f_iter;
1331
1332 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
1333 {
1334 generate_netstd_union_class(out, tunion, (*f_iter));
1335 }
1336
1337 generate_netstd_union_reader(out, tunion);
1338
1339 indent_down();
1340 out << indent() << "}" << endl << endl;
1341
1342 end_netstd_namespace(out);
1343 }
1344
1345 void t_netstd_generator::generate_netstd_union_class(ostream& out, t_struct* tunion, t_field* tfield)
1346 {
1347 out << indent() << "public " << type_name(tfield->get_type()) << " As_" << tfield->get_name() << endl;
1348 out << indent() << "{" << endl;
1349 indent_up();
1350 out << indent() << "get" << endl;
1351 out << indent() << "{" << endl;
1352 indent_up();
1353 out << indent() << "return (" << tfield->get_key() << " == Isset) ? (" << type_name(tfield->get_type()) << ")Data : default(" << type_name(tfield->get_type()) << ");" << endl;
1354 indent_down();
1355 out << indent() << "}" << endl;
1356 indent_down();
1357 out << indent() << "}" << endl
1358 << endl;
1359
1360
1361 out << indent() << "public class " << tfield->get_name() << " : " << tunion->get_name() << endl
1362 << indent() << "{" << endl;
1363 indent_up();
1364
1365 out << indent() << "private " << type_name(tfield->get_type()) << " _data;" << endl
1366 << indent() << "public override object Data { get { return _data; } }" << endl
1367 << indent() << "public " << tfield->get_name() << "(" << type_name(tfield->get_type()) << " data) : base("<< tfield->get_key() <<")" << endl
1368 << indent() << "{" << endl;
1369 indent_up();
1370 out << indent() << "this._data = data;" << endl;
1371 indent_down();
1372 out << indent() << "}" << endl;
1373
1374 out << indent() << "public override async Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken) {" << endl;
1375 indent_up();
1376
1377 out << indent() << "oprot.IncrementRecursionDepth();" << endl
1378 << indent() << "try" << endl
1379 << indent() << "{" << endl;
1380 indent_up();
1381
1382 out << indent() << "var struc = new TStruct(\"" << tunion->get_name() << "\");" << endl
1383 << indent() << "await oprot.WriteStructBeginAsync(struc, cancellationToken);" << endl;
1384
1385 out << indent() << "var field = new TField();" << endl
1386 << indent() << "field.Name = \"" << tfield->get_name() << "\";" << endl
1387 << indent() << "field.Type = " << type_to_enum(tfield->get_type()) << ";" << endl
1388 << indent() << "field.ID = " << tfield->get_key() << ";" << endl
1389 << indent() << "await oprot.WriteFieldBeginAsync(field, cancellationToken);" << endl;
1390
1391 generate_serialize_field(out, tfield, "_data", true);
1392
1393 out << indent() << "await oprot.WriteFieldEndAsync(cancellationToken);" << endl
1394 << indent() << "await oprot.WriteFieldStopAsync(cancellationToken);" << endl
1395 << indent() << "await oprot.WriteStructEndAsync(cancellationToken);" << endl;
1396 indent_down();
1397 out << indent() << "}" << endl
1398 << indent() << "finally" << endl
1399 << indent() << "{" << endl;
1400 indent_up();
1401 out << indent() << "oprot.DecrementRecursionDepth();" << endl;
1402 indent_down();
1403 out << indent() << "}" << endl;
1404 out << indent() << "}" << endl;
1405 indent_down();
1406 out << indent() << "}" << endl << endl;
1407 }
1408
1409 void t_netstd_generator::generate_netstd_struct_equals(ostream& out, t_struct* tstruct)
1410 {
1411 out << indent() << "public override bool Equals(object that)" << endl
1412 << indent() << "{" << endl;
1413 indent_up();
1414 out << indent() << "var other = that as " << check_and_correct_struct_name(normalize_name(tstruct->get_name())) << ";" << endl
1415 << indent() << "if (other == null) return false;" << endl
1416 << indent() << "if (ReferenceEquals(this, other)) return true;" << endl;
1417
1418 const vector<t_field*>& fields = tstruct->get_members();
1419 vector<t_field*>::const_iterator f_iter;
1420
1421 bool first = true;
1422
1423 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
1424 {
1425 if (first)
1426 {
1427 first = false;
1428 out << indent() << "return ";
1429 indent_up();
1430 }
1431 else
1432 {
1433 out << endl;
1434 out << indent() << "&& ";
1435 }
1436 if (!field_is_required((*f_iter)))
1437 {
1438 out << "((__isset." << normalize_name((*f_iter)->get_name()) << " == other.__isset."
1439 << normalize_name((*f_iter)->get_name()) << ") && ((!__isset."
1440 << normalize_name((*f_iter)->get_name()) << ") || (";
1441 }
1442 t_type* ttype = (*f_iter)->get_type();
1443 if (ttype->is_container() || ttype->is_binary())
1444 {
1445 out << "TCollections.Equals(";
1446 }
1447 else
1448 {
1449 out << "System.Object.Equals(";
1450 }
1451 out << prop_name((*f_iter)) << ", other." << prop_name((*f_iter)) << ")";
1452 if (!field_is_required((*f_iter)))
1453 {
1454 out << ")))";
1455 }
1456 }
1457 if (first)
1458 {
1459 out << indent() << "return true;" << endl;
1460 }
1461 else
1462 {
1463 out << ";" << endl;
1464 indent_down();
1465 }
1466
1467 indent_down();
1468 out << indent() << "}" << endl << endl;
1469 }
1470
1471 void t_netstd_generator::generate_netstd_struct_hashcode(ostream& out, t_struct* tstruct)
1472 {
1473 out << indent() << "public override int GetHashCode() {" << endl;
1474 indent_up();
1475
1476 out << indent() << "int hashcode = 157;" << endl;
1477 out << indent() << "unchecked {" << endl;
1478 indent_up();
1479
1480 const vector<t_field*>& fields = tstruct->get_members();
1481 vector<t_field*>::const_iterator f_iter;
1482
1483 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
1484 {
1485 t_type* ttype = (*f_iter)->get_type();
1486 if (!field_is_required((*f_iter)))
1487 {
1488 out << indent() << "if(__isset." << normalize_name((*f_iter)->get_name()) << ")" << endl;
1489 indent_up();
1490 }
1491 out << indent() << "hashcode = (hashcode * 397) + ";
1492 if (ttype->is_container())
1493 {
1494 out << "TCollections.GetHashCode(" << prop_name((*f_iter)) << ")";
1495 }
1496 else
1497 {
1498 out << prop_name((*f_iter)) << ".GetHashCode()";
1499 }
1500 out << ";" << endl;
1501
1502 if (!field_is_required((*f_iter)))
1503 {
1504 indent_down();
1505 }
1506 }
1507
1508 indent_down();
1509 out << indent() << "}" << endl;
1510 out << indent() << "return hashcode;" << endl;
1511
1512 indent_down();
1513 out << indent() << "}" << endl << endl;
1514 }
1515
1516 void t_netstd_generator::generate_service(t_service* tservice)
1517 {
1518 int ic = indent_count();
1519
1520 string f_service_name = namespace_dir_ + "/" + service_name_ + ".cs";
1521 ofstream_with_content_based_conditional_update f_service;
1522 f_service.open(f_service_name.c_str());
1523
1524 f_service << autogen_comment() << netstd_type_usings() << netstd_thrift_usings() << endl;
1525
1526 start_netstd_namespace(f_service);
1527
1528 f_service << indent() << "public partial class " << normalize_name(service_name_) << endl
1529 << indent() << "{" << endl;
1530 indent_up();
1531
1532 generate_service_interface(f_service, tservice);
1533 generate_service_client(f_service, tservice);
1534 generate_service_server(f_service, tservice);
1535 generate_service_helpers(f_service, tservice);
1536
1537 indent_down();
1538 f_service << indent() << "}" << endl;
1539
1540 end_netstd_namespace(f_service);
1541 f_service.close();
1542
1543 indent_validate(ic, "generate_service.");
1544 }
1545
1546 void t_netstd_generator::generate_service_interface(ostream& out, t_service* tservice)
1547 {
1548 string extends = "";
1549 string extends_iface = "";
1550 if (tservice->get_extends() != NULL)
1551 {
1552 extends = type_name(tservice->get_extends());
1553 extends_iface = " : " + extends + ".IAsync";
1554 }
1555
1556 //out << endl << endl;
1557
1558 generate_netstd_doc(out, tservice);
1559
1560 if (is_wcf_enabled())
1561 {
1562 out << indent() << "[ServiceContract(Namespace=\"" << wcf_namespace_ << "\")]" << endl;
1563 }
1564
1565 out << indent() << "public interface IAsync" << extends_iface << endl
1566 << indent() << "{" << endl;
1567
1568 indent_up();
1569 vector<t_function*> functions = tservice->get_functions();
1570 vector<t_function*>::iterator f_iter;
1571 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter)
1572 {
1573 generate_netstd_doc(out, *f_iter);
1574
1575 // if we're using WCF, add the corresponding attributes
1576 if (is_wcf_enabled())
1577 {
1578 out << indent() << "[OperationContract]" << endl;
1579
1580 const vector<t_field*>& xceptions = (*f_iter)->get_xceptions()->get_members();
1581 vector<t_field*>::const_iterator x_iter;
1582 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter)
1583 {
1584 out << indent() << "[FaultContract(typeof(" + type_name((*x_iter)->get_type()) + "Fault))]" << endl;
1585 }
1586 }
1587
1588 out << indent() << function_signature_async(*f_iter) << ";" << endl << endl;
1589 }
1590 indent_down();
1591 out << indent() << "}" << endl << endl;
1592 }
1593
1594 void t_netstd_generator::generate_service_helpers(ostream& out, t_service* tservice)
1595 {
1596 vector<t_function*> functions = tservice->get_functions();
1597 vector<t_function*>::iterator f_iter;
1598
1599 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter)
1600 {
1601 t_struct* ts = (*f_iter)->get_arglist();
1602 generate_netstd_struct_definition(out, ts, false, true);
1603 generate_function_helpers(out, *f_iter);
1604 }
1605 }
1606
1607 void t_netstd_generator::generate_service_client(ostream& out, t_service* tservice)
1608 {
1609 string extends = "";
1610 string extends_client = "";
1611 if (tservice->get_extends() != NULL)
1612 {
1613 extends = type_name(tservice->get_extends());
1614 extends_client = extends + ".Client, ";
1615 }
1616 else
1617 {
1618 extends_client = "TBaseClient, IDisposable, ";
1619 }
1620
1621 out << endl;
1622
1623 generate_netstd_doc(out, tservice);
1624
1625 out << indent() << "public class Client : " << extends_client << "IAsync" << endl
1626 << indent() << "{" << endl;
1627 indent_up();
1628
1629 out << indent() << "public Client(TProtocol protocol) : this(protocol, protocol)" << endl
1630 << indent() << "{" << endl
1631 << indent() << "}" << endl
1632 << endl
1633 << indent() << "public Client(TProtocol inputProtocol, TProtocol outputProtocol) : base(inputProtocol, outputProtocol)"
1634 << indent() << "{" << endl
1635 << indent() << "}" << endl;
1636
1637 vector<t_function*> functions = tservice->get_functions();
1638 vector<t_function*>::const_iterator functions_iterator;
1639
1640 for (functions_iterator = functions.begin(); functions_iterator != functions.end(); ++functions_iterator)
1641 {
1642 string function_name = correct_function_name_for_async((*functions_iterator)->get_name());
1643
1644 // async
1645 out << indent() << "public async " << function_signature_async(*functions_iterator, "") << endl
1646 << indent() << "{" << endl;
1647 indent_up();
1648
1649 string argsname = (*functions_iterator)->get_name() + "Args";
1650
1651 out << indent() << "await OutputProtocol.WriteMessageBeginAsync(new TMessage(\"" << function_name
1652 << "\", " << ((*functions_iterator)->is_oneway() ? "TMessageType.Oneway" : "TMessageType.Call") << ", SeqId), cancellationToken);" << endl
1653 << indent() << endl
1654 << indent() << "var args = new " << argsname << "();" << endl;
1655
1656 t_struct* arg_struct = (*functions_iterator)->get_arglist();
1657 prepare_member_name_mapping(arg_struct);
1658 const vector<t_field*>& fields = arg_struct->get_members();
1659 vector<t_field*>::const_iterator fld_iter;
1660
1661 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter)
1662 {
1663 out << indent() << "args." << prop_name(*fld_iter) << " = " << normalize_name((*fld_iter)->get_name()) << ";" << endl;
1664 }
1665
1666 out << indent() << endl
1667 << indent() << "await args.WriteAsync(OutputProtocol, cancellationToken);" << endl
1668 << indent() << "await OutputProtocol.WriteMessageEndAsync(cancellationToken);" << endl
1669 << indent() << "await OutputProtocol.Transport.FlushAsync(cancellationToken);" << endl;
1670
1671 if (!(*functions_iterator)->is_oneway())
1672 {
1673 string resultname = (*functions_iterator)->get_name() + "Result";
1674 t_struct noargs(program_);
1675 t_struct* xs = (*functions_iterator)->get_xceptions();
1676 prepare_member_name_mapping(xs, xs->get_members(), resultname);
1677
1678 out << indent() << endl
1679 << indent() << "var msg = await InputProtocol.ReadMessageBeginAsync(cancellationToken);" << endl
1680 << indent() << "if (msg.Type == TMessageType.Exception)" << endl
1681 << indent() << "{" << endl;
1682 indent_up();
1683
1684 out << indent() << "var x = await TApplicationException.ReadAsync(InputProtocol, cancellationToken);" << endl
1685 << indent() << "await InputProtocol.ReadMessageEndAsync(cancellationToken);" << endl
1686 << indent() << "throw x;" << endl;
1687 indent_down();
1688
1689 out << indent() << "}" << endl
1690 << endl
1691 << indent() << "var result = new " << resultname << "();" << endl
1692 << indent() << "await result.ReadAsync(InputProtocol, cancellationToken);" << endl
1693 << indent() << "await InputProtocol.ReadMessageEndAsync(cancellationToken);" << endl;
1694
1695 if (!(*functions_iterator)->get_returntype()->is_void())
1696 {
1697 out << indent() << "if (result.__isset.success)" << endl
1698 << indent() << "{" << endl;
1699 indent_up();
1700 out << indent() << "return result.Success;" << endl;
1701 indent_down();
1702 out << indent() << "}" << endl;
1703 }
1704
1705 const vector<t_field*>& xceptions = xs->get_members();
1706 vector<t_field*>::const_iterator x_iter;
1707 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter)
1708 {
1709 out << indent() << "if (result.__isset." << normalize_name((*x_iter)->get_name()) << ")" << endl
1710 << indent() << "{" << endl;
1711 indent_up();
1712 out << indent() << "throw result." << prop_name(*x_iter) << ";" << endl;
1713 indent_down();
1714 out << indent() << "}" << endl;
1715 }
1716
1717 if ((*functions_iterator)->get_returntype()->is_void())
1718 {
1719 out << indent() << "return;" << endl;
1720 }
1721 else
1722 {
1723 out << indent() << "throw new TApplicationException(TApplicationException.ExceptionType.MissingResult, \""
1724 << function_name << " failed: unknown result\");" << endl;
1725 }
1726
1727 cleanup_member_name_mapping((*functions_iterator)->get_xceptions());
1728 indent_down();
1729 out << indent() << "}" << endl << endl;
1730 }
1731 else
1732 {
1733 indent_down();
1734 out << indent() << "}" << endl;
1735 }
1736 }
1737
1738 indent_down();
1739 out << indent() << "}" << endl << endl;
1740 }
1741
1742 void t_netstd_generator::generate_service_server(ostream& out, t_service* tservice)
1743 {
1744 vector<t_function*> functions = tservice->get_functions();
1745 vector<t_function*>::iterator f_iter;
1746
1747 string extends = "";
1748 string extends_processor = "";
1749 if (tservice->get_extends() != NULL)
1750 {
1751 extends = type_name(tservice->get_extends());
1752 extends_processor = extends + ".AsyncProcessor, ";
1753 }
1754
1755 out << indent() << "public class AsyncProcessor : " << extends_processor << "ITAsyncProcessor" << endl
1756 << indent() << "{" << endl;
1757
1758 indent_up();
1759
1760 out << indent() << "private IAsync _iAsync;" << endl
1761 << endl
1762 << indent() << "public AsyncProcessor(IAsync iAsync)";
1763
1764 if (!extends.empty())
1765 {
1766 out << " : base(iAsync)";
1767 }
1768
1769 out << endl
1770 << indent() << "{" << endl;
1771 indent_up();
1772
1773 out << indent() << "if (iAsync == null) throw new ArgumentNullException(nameof(iAsync));" << endl
1774 << endl
1775 << indent() << "_iAsync = iAsync;" << endl;
1776
1777 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter)
1778 {
1779 string function_name = (*f_iter)->get_name();
1780 out << indent() << "processMap_[\"" << correct_function_name_for_async(function_name) << "\"] = " << function_name << "_ProcessAsync;" << endl;
1781 }
1782
1783 indent_down();
1784 out << indent() << "}" << endl
1785 << endl;
1786
1787 if (extends.empty())
1788 {
1789 out << indent() << "protected delegate Task ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken);" << endl;
1790 }
1791
1792 if (extends.empty())
1793 {
1794 out << indent() << "protected Dictionary<string, ProcessFunction> processMap_ = new Dictionary<string, ProcessFunction>();" << endl;
1795 }
1796
1797 out << endl;
1798
1799 if (extends.empty())
1800 {
1801 out << indent() << "public async Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot)" << endl
1802 << indent() << "{" << endl;
1803 indent_up();
1804 out << indent() << "return await ProcessAsync(iprot, oprot, CancellationToken.None);" << endl;
1805 indent_down();
1806 out << indent() << "}" << endl << endl;
1807
1808 out << indent() << "public async Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken)" << endl;
1809 }
1810 else
1811 {
1812 out << indent() << "public new async Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot)" << endl
1813 << indent() << "{" << endl;
1814 indent_up();
1815 out << indent() << "return await ProcessAsync(iprot, oprot, CancellationToken.None);" << endl;
1816 indent_down();
1817 out << indent() << "}" << endl << endl;
1818
1819 out << indent() << "public new async Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken)" << endl;
1820 }
1821
1822 out << indent() << "{" << endl;
1823 indent_up();
1824 out << indent() << "try" << endl
1825 << indent() << "{" << endl;
1826 indent_up();
1827 out << indent() << "var msg = await iprot.ReadMessageBeginAsync(cancellationToken);" << endl
1828 << endl
1829 << indent() << "ProcessFunction fn;" << endl
1830 << indent() << "processMap_.TryGetValue(msg.Name, out fn);" << endl
1831 << endl
1832 << indent() << "if (fn == null)" << endl
1833 << indent() << "{" << endl;
1834 indent_up();
1835 out << indent() << "await TProtocolUtil.SkipAsync(iprot, TType.Struct, cancellationToken);" << endl
1836 << indent() << "await iprot.ReadMessageEndAsync(cancellationToken);" << endl
1837 << indent() << "var x = new TApplicationException (TApplicationException.ExceptionType.UnknownMethod, \"Invalid method name: '\" + msg.Name + \"'\");" << endl
1838 << indent() << "await oprot.WriteMessageBeginAsync(new TMessage(msg.Name, TMessageType.Exception, msg.SeqID), cancellationToken);" << endl
1839 << indent() << "await x.WriteAsync(oprot, cancellationToken);" << endl
1840 << indent() << "await oprot.WriteMessageEndAsync(cancellationToken);" << endl
1841 << indent() << "await oprot.Transport.FlushAsync(cancellationToken);" << endl
1842 << indent() << "return true;" << endl;
1843 indent_down();
1844 out << indent() << "}" << endl
1845 << endl
1846 << indent() << "await fn(msg.SeqID, iprot, oprot, cancellationToken);" << endl
1847 << endl;
1848 indent_down();
1849 out << indent() << "}" << endl;
1850 out << indent() << "catch (IOException)" << endl
1851 << indent() << "{" << endl;
1852 indent_up();
1853 out << indent() << "return false;" << endl;
1854 indent_down();
1855 out << indent() << "}" << endl
1856 << endl
1857 << indent() << "return true;" << endl;
1858 indent_down();
1859 out << indent() << "}" << endl << endl;
1860
1861 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter)
1862 {
1863 generate_process_function_async(out, tservice, *f_iter);
1864 }
1865
1866 indent_down();
1867 out << indent() << "}" << endl << endl;
1868 }
1869
1870 void t_netstd_generator::generate_function_helpers(ostream& out, t_function* tfunction)
1871 {
1872 if (tfunction->is_oneway())
1873 {
1874 return;
1875 }
1876
1877 t_struct result(program_, tfunction->get_name() + "_result");
1878 t_field success(tfunction->get_returntype(), "success", 0);
1879 if (!tfunction->get_returntype()->is_void())
1880 {
1881 result.append(&success);
1882 }
1883
1884 t_struct* xs = tfunction->get_xceptions();
1885 const vector<t_field*>& fields = xs->get_members();
1886 vector<t_field*>::const_iterator f_iter;
1887 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
1888 {
1889 result.append(*f_iter);
1890 }
1891
1892 generate_netstd_struct_definition(out, &result, false, true, true);
1893 }
1894
1895 void t_netstd_generator::generate_process_function_async(ostream& out, t_service* tservice, t_function* tfunction)
1896 {
1897 (void)tservice;
1898 out << indent() << "public async Task " << tfunction->get_name()
1899 << "_ProcessAsync(int seqid, TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken)" << endl
1900 << indent() << "{" << endl;
1901 indent_up();
1902
1903 string argsname = tfunction->get_name() + "Args";
1904 string resultname = tfunction->get_name() + "Result";
1905
1906 out << indent() << "var args = new " << argsname << "();" << endl
1907 << indent() << "await args.ReadAsync(iprot, cancellationToken);" << endl
1908 << indent() << "await iprot.ReadMessageEndAsync(cancellationToken);" << endl;
1909
1910 if (!tfunction->is_oneway())
1911 {
1912 out << indent() << "var result = new " << resultname << "();" << endl;
1913 }
1914
1915 out << indent() << "try" << endl
1916 << indent() << "{" << endl;
1917 indent_up();
1918
1919 t_struct* xs = tfunction->get_xceptions();
1920 const vector<t_field*>& xceptions = xs->get_members();
1921
1922 if (xceptions.size() > 0)
1923 {
1924 out << indent() << "try" << endl
1925 << indent() << "{" << endl;
1926 indent_up();
1927 }
1928
1929 t_struct* arg_struct = tfunction->get_arglist();
1930 const vector<t_field*>& fields = arg_struct->get_members();
1931 vector<t_field*>::const_iterator f_iter;
1932
1933 out << indent();
1934 if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void())
1935 {
1936 out << "result.Success = ";
1937 }
1938
1939 out << "await _iAsync." << normalize_name(tfunction->get_name()) << "Async(";
1940
1941 bool first = true;
1942 prepare_member_name_mapping(arg_struct);
1943 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
1944 {
1945 if (first)
1946 {
1947 first = false;
1948 }
1949 else
1950 {
1951 out << ", ";
1952 }
1953
1954 out << "args." << prop_name(*f_iter);
1955 }
1956
1957 cleanup_member_name_mapping(arg_struct);
1958
1959 if (!first)
1960 {
1961 out << ", ";
1962 }
1963
1964 out << "cancellationToken);" << endl;
1965
1966 vector<t_field*>::const_iterator x_iter;
1967
1968 prepare_member_name_mapping(xs, xs->get_members(), resultname);
1969 if (xceptions.size() > 0)
1970 {
1971 indent_down();
1972 out << indent() << "}" << endl;
1973
1974 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter)
1975 {
1976 out << indent() << "catch (" << type_name((*x_iter)->get_type()) << " " << (*x_iter)->get_name() << ")" << endl
1977 << indent() << "{" << endl;
1978
1979 if (!tfunction->is_oneway())
1980 {
1981 indent_up();
1982 out << indent() << "result." << prop_name(*x_iter) << " = " << (*x_iter)->get_name() << ";" << endl;
1983 indent_down();
1984 }
1985 out << indent() << "}" << endl;
1986 }
1987 }
1988
1989 if (!tfunction->is_oneway())
1990 {
1991 out << indent() << "await oprot.WriteMessageBeginAsync(new TMessage(\""
1992 << correct_function_name_for_async(tfunction->get_name()) << "\", TMessageType.Reply, seqid), cancellationToken); " << endl
1993 << indent() << "await result.WriteAsync(oprot, cancellationToken);" << endl;
1994 }
1995 indent_down();
1996
1997 cleanup_member_name_mapping(xs);
1998
1999 out << indent() << "}" << endl
2000 << indent() << "catch (TTransportException)" << endl
2001 << indent() << "{" << endl
2002 << indent() << " throw;" << endl
2003 << indent() << "}" << endl
2004 << indent() << "catch (Exception ex)" << endl
2005 << indent() << "{" << endl;
2006 indent_up();
2007
2008 out << indent() << "Console.Error.WriteLine(\"Error occurred in processor:\");" << endl
2009 << indent() << "Console.Error.WriteLine(ex.ToString());" << endl;
2010
2011 if (tfunction->is_oneway())
2012 {
2013 indent_down();
2014 out << indent() << "}" << endl;
2015 }
2016 else
2017 {
2018 out << indent() << "var x = new TApplicationException(TApplicationException.ExceptionType.InternalError,\" Internal error.\");" << endl
2019 << indent() << "await oprot.WriteMessageBeginAsync(new TMessage(\"" << correct_function_name_for_async(tfunction->get_name())
2020 << "\", TMessageType.Exception, seqid), cancellationToken);" << endl
2021 << indent() << "await x.WriteAsync(oprot, cancellationToken);" << endl;
2022 indent_down();
2023
2024 out << indent() << "}" << endl
2025 << indent() << "await oprot.WriteMessageEndAsync(cancellationToken);" << endl
2026 << indent() << "await oprot.Transport.FlushAsync(cancellationToken);" << endl;
2027 }
2028
2029 indent_down();
2030 out << indent() << "}" << endl << endl;
2031 }
2032
2033 void t_netstd_generator::generate_netstd_union_reader(ostream& out, t_struct* tunion)
2034 {
2035 // Thanks to THRIFT-1768, we don't need to check for required fields in the union
2036 const vector<t_field*>& fields = tunion->get_members();
2037 vector<t_field*>::const_iterator f_iter;
2038
2039 out << indent() << "public static async Task<" << tunion->get_name() << "> ReadAsync(TProtocol iprot, CancellationToken cancellationToken)" << endl;
2040 scope_up(out);
2041
2042 out << indent() << "iprot.IncrementRecursionDepth();" << endl;
2043 out << indent() << "try" << endl;
2044 scope_up(out);
2045
2046 out << indent() << tunion->get_name() << " retval;" << endl;
2047 out << indent() << "await iprot.ReadStructBeginAsync(cancellationToken);" << endl;
2048 out << indent() << "TField field = await iprot.ReadFieldBeginAsync(cancellationToken);" << endl;
2049 // we cannot have the first field be a stop -- we must have a single field defined
2050 out << indent() << "if (field.Type == TType.Stop)" << endl;
2051 scope_up(out);
2052 out << indent() << "await iprot.ReadFieldEndAsync(cancellationToken);" << endl;
2053 out << indent() << "retval = new ___undefined();" << endl;
2054 scope_down(out);
2055 out << indent() << "else" << endl;
2056 scope_up(out);
2057 out << indent() << "switch (field.ID)" << endl;
2058 scope_up(out);
2059
2060 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
2061 {
2062 out << indent() << "case " << (*f_iter)->get_key() << ":" << endl;
2063 indent_up();
2064 out << indent() << "if (field.Type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
2065 indent_up();
2066
2067 out << indent() << type_name((*f_iter)->get_type()) << " temp;" << endl;
2068 generate_deserialize_field(out, (*f_iter), "temp", true);
2069 out << indent() << "retval = new " << (*f_iter)->get_name() << "(temp);" << endl;
2070
2071 indent_down();
2072 out << indent() << "} else { " << endl << indent() << " await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);"
2073 << endl << indent() << " retval = new ___undefined();" << endl << indent() << "}" << endl
2074 << indent() << "break;" << endl;
2075 indent_down();
2076 }
2077
2078 out << indent() << "default: " << endl;
2079 indent_up();
2080 out << indent() << "await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);" << endl << indent()
2081 << "retval = new ___undefined();" << endl;
2082 out << indent() << "break;" << endl;
2083 indent_down();
2084
2085 scope_down(out);
2086
2087 out << indent() << "await iprot.ReadFieldEndAsync(cancellationToken);" << endl;
2088
2089 out << indent() << "if ((await iprot.ReadFieldBeginAsync(cancellationToken)).Type != TType.Stop)" << endl;
2090 scope_up(out);
2091 out << indent() << "throw new TProtocolException(TProtocolException.INVALID_DATA);" << endl;
2092 scope_down(out);
2093
2094 // end of else for TStop
2095 scope_down(out);
2096 out << indent() << "await iprot.ReadStructEndAsync(cancellationToken);" << endl;
2097 out << indent() << "return retval;" << endl;
2098 indent_down();
2099
2100 scope_down(out);
2101 out << indent() << "finally" << endl;
2102 scope_up(out);
2103 out << indent() << "iprot.DecrementRecursionDepth();" << endl;
2104 scope_down(out);
2105
2106 out << indent() << "}" << endl << endl;
2107 }
2108
2109 void t_netstd_generator::generate_deserialize_field(ostream& out, t_field* tfield, string prefix, bool is_propertyless)
2110 {
2111 t_type* type = tfield->get_type();
2112 while (type->is_typedef())
2113 {
2114 type = static_cast<t_typedef*>(type)->get_type();
2115 }
2116
2117 if (type->is_void())
2118 {
2119 throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
2120 }
2121
2122 string name = prefix + (is_propertyless ? "" : prop_name(tfield));
2123
2124 if (type->is_struct() || type->is_xception())
2125 {
2126 generate_deserialize_struct(out, static_cast<t_struct*>(type), name);
2127 }
2128 else if (type->is_container())
2129 {
2130 generate_deserialize_container(out, type, name);
2131 }
2132 else if (type->is_base_type() || type->is_enum())
2133 {
2134 out << indent() << name << " = ";
2135
2136 if (type->is_enum())
2137 {
2138 out << "(" << type_name(type) << ")";
2139 }
2140
2141 out << "await iprot.";
2142
2143 if (type->is_base_type())
2144 {
2145 t_base_type::t_base tbase = static_cast<t_base_type*>(type)->get_base();
2146 switch (tbase)
2147 {
2148 case t_base_type::TYPE_VOID:
2149 throw "compiler error: cannot serialize void field in a struct: " + name;
2150 break;
2151 case t_base_type::TYPE_STRING:
2152 if (type->is_binary())
2153 {
2154 out << "ReadBinaryAsync(cancellationToken);";
2155 }
2156 else
2157 {
2158 out << "ReadStringAsync(cancellationToken);";
2159 }
2160 break;
2161 case t_base_type::TYPE_BOOL:
2162 out << "ReadBoolAsync(cancellationToken);";
2163 break;
2164 case t_base_type::TYPE_I8:
2165 out << "ReadByteAsync(cancellationToken);";
2166 break;
2167 case t_base_type::TYPE_I16:
2168 out << "ReadI16Async(cancellationToken);";
2169 break;
2170 case t_base_type::TYPE_I32:
2171 out << "ReadI32Async(cancellationToken);";
2172 break;
2173 case t_base_type::TYPE_I64:
2174 out << "ReadI64Async(cancellationToken);";
2175 break;
2176 case t_base_type::TYPE_DOUBLE:
2177 out << "ReadDoubleAsync(cancellationToken);";
2178 break;
2179 default:
2180 throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase);
2181 }
2182 }
2183 else if (type->is_enum())
2184 {
2185 out << "ReadI32Async(cancellationToken);";
2186 }
2187 out << endl;
2188 }
2189 else
2190 {
2191 printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", tfield->get_name().c_str(), type_name(type).c_str());
2192 }
2193 }
2194
2195 void t_netstd_generator::generate_deserialize_struct(ostream& out, t_struct* tstruct, string prefix)
2196 {
2197 if (is_union_enabled() && tstruct->is_union())
2198 {
2199 out << indent() << prefix << " = await " << type_name(tstruct) << ".ReadAsync(iprot, cancellationToken);" << endl;
2200 }
2201 else
2202 {
2203 out << indent() << prefix << " = new " << type_name(tstruct) << "();" << endl
2204 << indent() << "await " << prefix << ".ReadAsync(iprot, cancellationToken);" << endl;
2205 }
2206 }
2207
2208 void t_netstd_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix)
2209 {
2210 out << indent() << "{" << endl;
2211 indent_up();
2212
2213 string obj;
2214
2215 if (ttype->is_map())
2216 {
2217 obj = tmp("_map");
2218 }
2219 else if (ttype->is_set())
2220 {
2221 obj = tmp("_set");
2222 }
2223 else if (ttype->is_list())
2224 {
2225 obj = tmp("_list");
2226 }
2227
2228 if (ttype->is_map())
2229 {
2230 out << indent() << "TMap " << obj << " = await iprot.ReadMapBeginAsync(cancellationToken);" << endl;
2231 }
2232 else if (ttype->is_set())
2233 {
2234 out << indent() << "TSet " << obj << " = await iprot.ReadSetBeginAsync(cancellationToken);" << endl;
2235 }
2236 else if (ttype->is_list())
2237 {
2238 out << indent() << "TList " << obj << " = await iprot.ReadListBeginAsync(cancellationToken);" << endl;
2239 }
2240
2241 out << indent() << prefix << " = new " << type_name(ttype) << "(" << obj << ".Count);" << endl;
2242 string i = tmp("_i");
2243 out << indent() << "for(int " << i << " = 0; " << i << " < " << obj << ".Count; ++" << i << ")" << endl
2244 << indent() << "{" << endl;
2245 indent_up();
2246
2247 if (ttype->is_map())
2248 {
2249 generate_deserialize_map_element(out, static_cast<t_map*>(ttype), prefix);
2250 }
2251 else if (ttype->is_set())
2252 {
2253 generate_deserialize_set_element(out, static_cast<t_set*>(ttype), prefix);
2254 }
2255 else if (ttype->is_list())
2256 {
2257 generate_deserialize_list_element(out, static_cast<t_list*>(ttype), prefix);
2258 }
2259
2260 indent_down();
2261 out << indent() << "}" << endl;
2262
2263 if (ttype->is_map())
2264 {
2265 out << indent() << "await iprot.ReadMapEndAsync(cancellationToken);" << endl;
2266 }
2267 else if (ttype->is_set())
2268 {
2269 out << indent() << "await iprot.ReadSetEndAsync(cancellationToken);" << endl;
2270 }
2271 else if (ttype->is_list())
2272 {
2273 out << indent() << "await iprot.ReadListEndAsync(cancellationToken);" << endl;
2274 }
2275
2276 indent_down();
2277 out << indent() << "}" << endl;
2278 }
2279
2280 void t_netstd_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix)
2281 {
2282 string key = tmp("_key");
2283 string val = tmp("_val");
2284
2285 t_field fkey(tmap->get_key_type(), key);
2286 t_field fval(tmap->get_val_type(), val);
2287
2288 out << indent() << declare_field(&fkey) << endl;
2289 out << indent() << declare_field(&fval) << endl;
2290
2291 generate_deserialize_field(out, &fkey);
2292 generate_deserialize_field(out, &fval);
2293
2294 out << indent() << prefix << "[" << key << "] = " << val << ";" << endl;
2295 }
2296
2297 void t_netstd_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix)
2298 {
2299 string elem = tmp("_elem");
2300 t_field felem(tset->get_elem_type(), elem);
2301
2302 out << indent() << declare_field(&felem) << endl;
2303
2304 generate_deserialize_field(out, &felem);
2305
2306 out << indent() << prefix << ".Add(" << elem << ");" << endl;
2307 }
2308
2309 void t_netstd_generator::generate_deserialize_list_element(ostream& out, t_list* tlist, string prefix)
2310 {
2311 string elem = tmp("_elem");
2312 t_field felem(tlist->get_elem_type(), elem);
2313
2314 out << indent() << declare_field(&felem) << endl;
2315
2316 generate_deserialize_field(out, &felem);
2317
2318 out << indent() << prefix << ".Add(" << elem << ");" << endl;
2319 }
2320
2321 void t_netstd_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix, bool is_propertyless)
2322 {
2323 t_type* type = tfield->get_type();
2324 while (type->is_typedef())
2325 {
2326 type = static_cast<t_typedef*>(type)->get_type();
2327 }
2328
2329 string name = prefix + (is_propertyless ? "" : prop_name(tfield));
2330
2331 if (type->is_void())
2332 {
2333 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name;
2334 }
2335
2336 if (type->is_struct() || type->is_xception())
2337 {
2338 generate_serialize_struct(out, static_cast<t_struct*>(type), name);
2339 }
2340 else if (type->is_container())
2341 {
2342 generate_serialize_container(out, type, name);
2343 }
2344 else if (type->is_base_type() || type->is_enum())
2345 {
2346 out << indent() << "await oprot.";
2347
2348 string nullable_name = name;
2349
2350 if (type->is_base_type())
2351 {
2352 t_base_type::t_base tbase = static_cast<t_base_type*>(type)->get_base();
2353 switch (tbase)
2354 {
2355 case t_base_type::TYPE_VOID:
2356 throw "compiler error: cannot serialize void field in a struct: " + name;
2357 case t_base_type::TYPE_STRING:
2358 if (type->is_binary())
2359 {
2360 out << "WriteBinaryAsync(";
2361 }
2362 else
2363 {
2364 out << "WriteStringAsync(";
2365 }
2366 out << name << ", cancellationToken);";
2367 break;
2368 case t_base_type::TYPE_BOOL:
2369 out << "WriteBoolAsync(" << nullable_name << ", cancellationToken);";
2370 break;
2371 case t_base_type::TYPE_I8:
2372 out << "WriteByteAsync(" << nullable_name << ", cancellationToken);";
2373 break;
2374 case t_base_type::TYPE_I16:
2375 out << "WriteI16Async(" << nullable_name << ", cancellationToken);";
2376 break;
2377 case t_base_type::TYPE_I32:
2378 out << "WriteI32Async(" << nullable_name << ", cancellationToken);";
2379 break;
2380 case t_base_type::TYPE_I64:
2381 out << "WriteI64Async(" << nullable_name << ", cancellationToken);";
2382 break;
2383 case t_base_type::TYPE_DOUBLE:
2384 out << "WriteDoubleAsync(" << nullable_name << ", cancellationToken);";
2385 break;
2386 default:
2387 throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase);
2388 }
2389 }
2390 else if (type->is_enum())
2391 {
2392 out << "WriteI32Async((int)" << nullable_name << ", cancellationToken);";
2393 }
2394 out << endl;
2395 }
2396 else
2397 {
2398 printf("DO NOT KNOW HOW TO SERIALIZE '%s%s' TYPE '%s'\n", prefix.c_str(), tfield->get_name().c_str(), type_name(type).c_str());
2399 }
2400 }
2401
2402 void t_netstd_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix)
2403 {
2404 (void)tstruct;
2405 out << indent() << "await " << prefix << ".WriteAsync(oprot, cancellationToken);" << endl;
2406 }
2407
2408 void t_netstd_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix)
2409 {
2410 out << indent() << "{" << endl;
2411 indent_up();
2412
2413 if (ttype->is_map())
2414 {
2415 out << indent() << "await oprot.WriteMapBeginAsync(new TMap(" << type_to_enum(static_cast<t_map*>(ttype)->get_key_type())
2416 << ", " << type_to_enum(static_cast<t_map*>(ttype)->get_val_type()) << ", " << prefix
2417 << ".Count), cancellationToken);" << endl;
2418 }
2419 else if (ttype->is_set())
2420 {
2421 out << indent() << "await oprot.WriteSetBeginAsync(new TSet(" << type_to_enum(static_cast<t_set*>(ttype)->get_elem_type())
2422 << ", " << prefix << ".Count), cancellationToken);" << endl;
2423 }
2424 else if (ttype->is_list())
2425 {
2426 out << indent() << "await oprot.WriteListBeginAsync(new TList("
2427 << type_to_enum(static_cast<t_list*>(ttype)->get_elem_type()) << ", " << prefix << ".Count), cancellationToken);"
2428 << endl;
2429 }
2430
2431 string iter = tmp("_iter");
2432 if (ttype->is_map())
2433 {
2434 out << indent() << "foreach (" << type_name(static_cast<t_map*>(ttype)->get_key_type()) << " " << iter
2435 << " in " << prefix << ".Keys)";
2436 }
2437 else if (ttype->is_set())
2438 {
2439 out << indent() << "foreach (" << type_name(static_cast<t_set*>(ttype)->get_elem_type()) << " " << iter
2440 << " in " << prefix << ")";
2441 }
2442 else if (ttype->is_list())
2443 {
2444 out << indent() << "foreach (" << type_name(static_cast<t_list*>(ttype)->get_elem_type()) << " " << iter
2445 << " in " << prefix << ")";
2446 }
2447
2448 out << endl;
2449 out << indent() << "{" << endl;
2450 indent_up();
2451
2452 if (ttype->is_map())
2453 {
2454 generate_serialize_map_element(out, static_cast<t_map*>(ttype), iter, prefix);
2455 }
2456 else if (ttype->is_set())
2457 {
2458 generate_serialize_set_element(out, static_cast<t_set*>(ttype), iter);
2459 }
2460 else if (ttype->is_list())
2461 {
2462 generate_serialize_list_element(out, static_cast<t_list*>(ttype), iter);
2463 }
2464
2465 indent_down();
2466 out << indent() << "}" << endl;
2467
2468 if (ttype->is_map())
2469 {
2470 out << indent() << "await oprot.WriteMapEndAsync(cancellationToken);" << endl;
2471 }
2472 else if (ttype->is_set())
2473 {
2474 out << indent() << "await oprot.WriteSetEndAsync(cancellationToken);" << endl;
2475 }
2476 else if (ttype->is_list())
2477 {
2478 out << indent() << "await oprot.WriteListEndAsync(cancellationToken);" << endl;
2479 }
2480
2481 indent_down();
2482 out << indent() << "}" << endl;
2483 }
2484
2485 void t_netstd_generator::generate_serialize_map_element(ostream& out, t_map* tmap, string iter, string map)
2486 {
2487 t_field kfield(tmap->get_key_type(), iter);
2488 generate_serialize_field(out, &kfield, "");
2489 t_field vfield(tmap->get_val_type(), map + "[" + iter + "]");
2490 generate_serialize_field(out, &vfield, "");
2491 }
2492
2493 void t_netstd_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter)
2494 {
2495 t_field efield(tset->get_elem_type(), iter);
2496 generate_serialize_field(out, &efield, "");
2497 }
2498
2499 void t_netstd_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter)
2500 {
2501 t_field efield(tlist->get_elem_type(), iter);
2502 generate_serialize_field(out, &efield, "");
2503 }
2504
2505 void t_netstd_generator::generate_property(ostream& out, t_field* tfield, bool isPublic, bool generateIsset)
2506 {
2507 generate_netstd_property(out, tfield, isPublic, generateIsset, "_");
2508 }
2509
2510 void t_netstd_generator::generate_netstd_property(ostream& out, t_field* tfield, bool isPublic, bool generateIsset, string fieldPrefix)
2511 {
2512 if ((is_serialize_enabled() || is_wcf_enabled()) && isPublic)
2513 {
2514 out << indent() << "[DataMember(Order = 0)]" << endl;
2515 }
2516 bool is_required = field_is_required(tfield);
2517 if (is_required)
2518 {
2519 out << indent() << (isPublic ? "public " : "private ") << type_name(tfield->get_type()) << " " << prop_name(tfield) << " { get; set; }" << endl;
2520 }
2521 else
2522 {
2523 out << indent() << (isPublic ? "public " : "private ") << type_name(tfield->get_type()) << " " << prop_name(tfield) << endl
2524 << indent() << "{" << endl;
2525 indent_up();
2526
2527 out << indent() << "get" << endl
2528 << indent() << "{" << endl;
2529 indent_up();
2530
2531 bool use_nullable = false;
2532
2533 out << indent() << "return " << fieldPrefix + tfield->get_name() << ";" << endl;
2534 indent_down();
2535 out << indent() << "}" << endl
2536 << indent() << "set" << endl
2537 << indent() << "{" << endl;
2538 indent_up();
2539
2540 if (use_nullable)
2541 {
2542 if (generateIsset)
2543 {
2544 out << indent() << "__isset." << normalize_name(tfield->get_name()) << " = value.HasValue;" << endl;
2545 }
2546 out << indent() << "if (value.HasValue) this." << fieldPrefix + tfield->get_name() << " = value.Value;" << endl;
2547 }
2548 else
2549 {
2550 if (generateIsset)
2551 {
2552 out << indent() << "__isset." << normalize_name(tfield->get_name()) << " = true;" << endl;
2553 }
2554 out << indent() << "this." << fieldPrefix + tfield->get_name() << " = value;" << endl;
2555 }
2556
2557 indent_down();
2558 out << indent() << "}" << endl;
2559 indent_down();
2560 out << indent() << "}" << endl;
2561 }
2562 out << endl;
2563 }
2564
2565 string t_netstd_generator::make_valid_csharp_identifier(string const& fromName)
2566 {
2567 string str = fromName;
2568 if (str.empty())
2569 {
2570 return str;
2571 }
2572
2573 // tests rely on this
2574 assert(('A' < 'Z') && ('a' < 'z') && ('0' < '9'));
2575
2576 // if the first letter is a number, we add an additional underscore in front of it
2577 char c = str.at(0);
2578 if (('0' <= c) && (c <= '9'))
2579 {
2580 str = "_" + str;
2581 }
2582
2583 // following chars: letter, number or underscore
2584 for (size_t i = 0; i < str.size(); ++i)
2585 {
2586 c = str.at(i);
2587 if (('A' > c || c > 'Z') && ('a' > c || c > 'z') && ('0' > c || c > '9') && '_' != c)
2588 {
2589 str.replace(i, 1, "_");
2590 }
2591 }
2592
2593 return str;
2594 }
2595
2596 void t_netstd_generator::cleanup_member_name_mapping(void* scope)
2597 {
2598 if (member_mapping_scopes.empty())
2599 {
2600 throw "internal error: cleanup_member_name_mapping() no scope active";
2601 }
2602
2603 member_mapping_scope& active = member_mapping_scopes.back();
2604 if (active.scope_member != scope)
2605 {
2606 throw "internal error: cleanup_member_name_mapping() called for wrong struct";
2607 }
2608
2609 member_mapping_scopes.pop_back();
2610 }
2611
2612 string t_netstd_generator::get_mapped_member_name(string name)
2613 {
2614 if (!member_mapping_scopes.empty())
2615 {
2616 member_mapping_scope& active = member_mapping_scopes.back();
2617 map<string, string>::iterator iter = active.mapping_table.find(name);
2618 if (active.mapping_table.end() != iter)
2619 {
2620 return iter->second;
2621 }
2622 }
2623
2624 pverbose("no mapping for member %s\n", name.c_str());
2625 return name;
2626 }
2627
2628 void t_netstd_generator::prepare_member_name_mapping(t_struct* tstruct)
2629 {
2630 prepare_member_name_mapping(tstruct, tstruct->get_members(), tstruct->get_name());
2631 }
2632
2633 void t_netstd_generator::prepare_member_name_mapping(void* scope, const vector<t_field*>& members, const string& structname)
2634 {
2635 // begin new scope
2636 member_mapping_scopes.emplace_back();
2637 member_mapping_scope& active = member_mapping_scopes.back();
2638 active.scope_member = scope;
2639
2640 // current C# generator policy:
2641 // - prop names are always rendered with an Uppercase first letter
2642 // - struct names are used as given
2643 std::set<string> used_member_names;
2644 vector<t_field*>::const_iterator iter;
2645
2646 // prevent name conflicts with struct (CS0542 error)
2647 used_member_names.insert(structname);
2648
2649 // prevent name conflicts with known methods (THRIFT-2942)
2650 used_member_names.insert("Read");
2651 used_member_names.insert("Write");
2652
2653 for (iter = members.begin(); iter != members.end(); ++iter)
2654 {
2655 string oldname = (*iter)->get_name();
2656 string newname = prop_name(*iter, true);
2657 while (true)
2658 {
2659 // new name conflicts with another member
2660 if (used_member_names.find(newname) != used_member_names.end())
2661 {
2662 pverbose("struct %s: member %s conflicts with another member\n", structname.c_str(), newname.c_str());
2663 newname += '_';
2664 continue;
2665 }
2666
2667 // add always, this helps us to detect edge cases like
2668 // different spellings ("foo" and "Foo") within the same struct
2669 pverbose("struct %s: member mapping %s => %s\n", structname.c_str(), oldname.c_str(), newname.c_str());
2670 active.mapping_table[oldname] = newname;
2671 used_member_names.insert(newname);
2672 break;
2673 }
2674 }
2675 }
2676
2677 string t_netstd_generator::prop_name(t_field* tfield, bool suppress_mapping)
2678 {
2679 string name(tfield->get_name());
2680 if (suppress_mapping)
2681 {
2682 name[0] = toupper(name[0]);
2683 }
2684 else
2685 {
2686 name = get_mapped_member_name(name);
2687 }
2688 return name;
2689 }
2690
2691 string t_netstd_generator::type_name(t_type* ttype)
2692 {
2693 while (ttype->is_typedef())
2694 {
2695 ttype = static_cast<t_typedef*>(ttype)->get_type();
2696 }
2697
2698 if (ttype->is_base_type())
2699 {
2700 return base_type_name(static_cast<t_base_type*>(ttype));
2701 }
2702
2703 if (ttype->is_map())
2704 {
2705 t_map* tmap = static_cast<t_map*>(ttype);
2706 return "Dictionary<" + type_name(tmap->get_key_type()) + ", " + type_name(tmap->get_val_type()) + ">";
2707 }
2708
2709 if (ttype->is_set())
2710 {
2711 t_set* tset = static_cast<t_set*>(ttype);
2712 return "THashSet<" + type_name(tset->get_elem_type()) + ">";
2713 }
2714
2715 if (ttype->is_list())
2716 {
2717 t_list* tlist = static_cast<t_list*>(ttype);
2718 return "List<" + type_name(tlist->get_elem_type()) + ">";
2719 }
2720
2721 t_program* program = ttype->get_program();
2722 if (program != NULL && program != program_)
2723 {
2724 string ns = program->get_namespace("netstd");
2725 if (!ns.empty())
2726 {
2727 return ns + "." + normalize_name(ttype->get_name());
2728 }
2729 }
2730
2731 return normalize_name(ttype->get_name());
2732 }
2733
2734 string t_netstd_generator::base_type_name(t_base_type* tbase)
2735 {
2736 switch (tbase->get_base())
2737 {
2738 case t_base_type::TYPE_VOID:
2739 return "void";
2740 case t_base_type::TYPE_STRING:
2741 {
2742 if (tbase->is_binary())
2743 {
2744 return "byte[]";
2745 }
2746 return "string";
2747 }
2748 case t_base_type::TYPE_BOOL:
2749 return "bool";
2750 case t_base_type::TYPE_I8:
2751 return "sbyte";
2752 case t_base_type::TYPE_I16:
2753 return "short";
2754 case t_base_type::TYPE_I32:
2755 return "int";
2756 case t_base_type::TYPE_I64:
2757 return "long";
2758 case t_base_type::TYPE_DOUBLE:
2759 return "double";
2760 default:
2761 throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase->get_base());
2762 }
2763 }
2764
2765 string t_netstd_generator::declare_field(t_field* tfield, bool init, string prefix)
2766 {
2767 string result = type_name(tfield->get_type()) + " " + prefix + tfield->get_name();
2768 if (init)
2769 {
2770 t_type* ttype = tfield->get_type();
2771 while (ttype->is_typedef())
2772 {
2773 ttype = static_cast<t_typedef*>(ttype)->get_type();
2774 }
2775 if (ttype->is_base_type() && field_has_default(tfield))
2776 {
2777 std::ofstream dummy;
2778 result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value());
2779 }
2780 else if (ttype->is_base_type())
2781 {
2782 t_base_type::t_base tbase = static_cast<t_base_type*>(ttype)->get_base();
2783 switch (tbase)
2784 {
2785 case t_base_type::TYPE_VOID:
2786 throw "NO T_VOID CONSTRUCT";
2787 case t_base_type::TYPE_STRING:
2788 result += " = null";
2789 break;
2790 case t_base_type::TYPE_BOOL:
2791 result += " = false";
2792 break;
2793 case t_base_type::TYPE_I8:
2794 case t_base_type::TYPE_I16:
2795 case t_base_type::TYPE_I32:
2796 case t_base_type::TYPE_I64:
2797 result += " = 0";
2798 break;
2799 case t_base_type::TYPE_DOUBLE:
2800 result += " = (double)0";
2801 break;
2802 }
2803 }
2804 else if (ttype->is_enum())
2805 {
2806 result += " = (" + type_name(ttype) + ")0";
2807 }
2808 else if (ttype->is_container())
2809 {
2810 result += " = new " + type_name(ttype) + "()";
2811 }
2812 else
2813 {
2814 result += " = new " + type_name(ttype) + "()";
2815 }
2816 }
2817 return result + ";";
2818 }
2819
2820 string t_netstd_generator::function_signature(t_function* tfunction, string prefix)
2821 {
2822 t_type* ttype = tfunction->get_returntype();
2823 return type_name(ttype) + " " + normalize_name(prefix + tfunction->get_name()) + "(" + argument_list(tfunction->get_arglist()) + ")";
2824 }
2825
2826 string t_netstd_generator::function_signature_async(t_function* tfunction, string prefix)
2827 {
2828 t_type* ttype = tfunction->get_returntype();
2829 string task = "Task";
2830 if (!ttype->is_void())
2831 {
2832 task += "<" + type_name(ttype) + ">";
2833 }
2834
2835 string result = task + " " + normalize_name(prefix + tfunction->get_name()) + "Async(";
2836 string args = argument_list(tfunction->get_arglist());
2837 result += args;
2838 if (!args.empty())
2839 {
2840 result += ", ";
2841 }
2842 result += "CancellationToken cancellationToken = default(CancellationToken))";
2843
2844 return result;
2845 }
2846
2847 string t_netstd_generator::argument_list(t_struct* tstruct)
2848 {
2849 string result = "";
2850 const vector<t_field*>& fields = tstruct->get_members();
2851 vector<t_field*>::const_iterator f_iter;
2852 bool first = true;
2853 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
2854 {
2855 if (first)
2856 {
2857 first = false;
2858 }
2859 else
2860 {
2861 result += ", ";
2862 }
2863 result += type_name((*f_iter)->get_type()) + " " + normalize_name((*f_iter)->get_name());
2864 }
2865 return result;
2866 }
2867
2868 string t_netstd_generator::type_to_enum(t_type* type)
2869 {
2870 while (type->is_typedef())
2871 {
2872 type = static_cast<t_typedef*>(type)->get_type();
2873 }
2874
2875 if (type->is_base_type())
2876 {
2877 t_base_type::t_base tbase = static_cast<t_base_type*>(type)->get_base();
2878 switch (tbase)
2879 {
2880 case t_base_type::TYPE_VOID:
2881 throw "NO T_VOID CONSTRUCT";
2882 case t_base_type::TYPE_STRING:
2883 return "TType.String";
2884 case t_base_type::TYPE_BOOL:
2885 return "TType.Bool";
2886 case t_base_type::TYPE_I8:
2887 return "TType.Byte";
2888 case t_base_type::TYPE_I16:
2889 return "TType.I16";
2890 case t_base_type::TYPE_I32:
2891 return "TType.I32";
2892 case t_base_type::TYPE_I64:
2893 return "TType.I64";
2894 case t_base_type::TYPE_DOUBLE:
2895 return "TType.Double";
2896 }
2897 }
2898 else if (type->is_enum())
2899 {
2900 return "TType.I32";
2901 }
2902 else if (type->is_struct() || type->is_xception())
2903 {
2904 return "TType.Struct";
2905 }
2906 else if (type->is_map())
2907 {
2908 return "TType.Map";
2909 }
2910 else if (type->is_set())
2911 {
2912 return "TType.Set";
2913 }
2914 else if (type->is_list())
2915 {
2916 return "TType.List";
2917 }
2918
2919 throw "INVALID TYPE IN type_to_enum: " + type->get_name();
2920 }
2921
2922 void t_netstd_generator::generate_netstd_docstring_comment(ostream& out, string contents)
2923 {
2924 docstring_comment(out, "/// <summary>" + endl, "/// ", contents, "/// </summary>" + endl);
2925 }
2926
2927 void t_netstd_generator::generate_netstd_doc(ostream& out, t_field* field)
2928 {
2929 if (field->get_type()->is_enum())
2930 {
2931 string combined_message = field->get_doc() + endl + "<seealso cref=\"" + get_enum_class_name(field->get_type()) + "\"/>";
2932 generate_netstd_docstring_comment(out, combined_message);
2933 }
2934 else
2935 {
2936 generate_netstd_doc(out, static_cast<t_doc*>(field));
2937 }
2938 }
2939
2940 void t_netstd_generator::generate_netstd_doc(ostream& out, t_doc* tdoc)
2941 {
2942 if (tdoc->has_doc())
2943 {
2944 generate_netstd_docstring_comment(out, tdoc->get_doc());
2945 }
2946 }
2947
2948 void t_netstd_generator::generate_netstd_doc(ostream& out, t_function* tfunction)
2949 {
2950 if (tfunction->has_doc())
2951 {
2952 stringstream ps;
2953 const vector<t_field*>& fields = tfunction->get_arglist()->get_members();
2954 vector<t_field*>::const_iterator p_iter;
2955 for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter)
2956 {
2957 t_field* p = *p_iter;
2958 ps << endl << "<param name=\"" << p->get_name() << "\">";
2959 if (p->has_doc())
2960 {
2961 string str = p->get_doc();
2962 str.erase(remove(str.begin(), str.end(), '\n'), str.end());
2963 ps << str;
2964 }
2965 ps << "</param>";
2966 }
2967
2968 docstring_comment(out,
2969 "",
2970 "/// ",
2971 "<summary>" + endl + tfunction->get_doc() + "</summary>" + ps.str(),
2972 "");
2973 }
2974 }
2975
2976 void t_netstd_generator::docstring_comment(ostream& out, const string& comment_start, const string& line_prefix, const string& contents, const string& comment_end)
2977 {
2978 if (comment_start != "")
2979 {
2980 out << indent() << comment_start;
2981 }
2982
2983 stringstream docs(contents, std::ios_base::in);
2984
2985 while (!(docs.eof() || docs.fail()))
2986 {
2987 char line[1024];
2988 docs.getline(line, 1024);
2989
2990 // Just prnt a newline when the line & prefix are empty.
2991 if (strlen(line) == 0 && line_prefix == "" && !docs.eof())
2992 {
2993 out << endl;
2994 }
2995 else if (strlen(line) > 0 || !docs.eof())
2996 { // skip the empty last line
2997 out << indent() << line_prefix << line << endl;
2998 }
2999 }
3000 if (comment_end != "")
3001 {
3002 out << indent() << comment_end;
3003 }
3004 }
3005
3006 string t_netstd_generator::get_enum_class_name(t_type* type)
3007 {
3008 string package = "";
3009 t_program* program = type->get_program();
3010 if (program != NULL && program != program_)
3011 {
3012 package = program->get_namespace("netstd") + ".";
3013 }
3014 return package + type->get_name();
3015 }
3016
3017 THRIFT_REGISTER_GENERATOR(
3018 netstd,
3019 "C#",
3020 " wcf: Adds bindings for WCF to generated classes.\n"
3021 " serial: Add serialization support to generated classes.\n"
3022 " union: Use new union typing, which includes a static read function for union types.\n"
3023 )