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
10 * http://www.apache.org/licenses/LICENSE-2.0
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
19 * Contains some contributions under the Thrift Software License.
20 * Please see doc/old-thrift-license.txt in the Thrift distribution for
36 #include "thrift/platform.h"
37 #include "thrift/generate/t_oop_generator.h"
38 #include "thrift/generate/t_netstd_generator.h"
42 using std::ostringstream
;
44 using std::stringstream
;
47 //TODO: check for indentation
48 //TODO: Do we need seqId_ in generation?
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
)
58 wcf_namespace_
.clear();
60 map
<string
, string
>::const_iterator iter
;
62 for (iter
= parsed_options
.begin(); iter
!= parsed_options
.end(); ++iter
)
64 if (iter
->first
.compare("union") == 0)
68 else if (iter
->first
.compare("serial") == 0)
71 wcf_namespace_
= iter
->second
; // since there can be only one namespace
73 else if (iter
->first
.compare("wcf") == 0)
76 wcf_namespace_
= iter
->second
;
80 throw "unknown option netstd:" + iter
->first
;
84 out_dir_base_
= "gen-netstd";
87 static string
correct_function_name_for_async(string
const& function_name
)
89 string
const async_end
= "Async";
90 size_t i
= function_name
.find(async_end
);
91 if (i
!= string::npos
)
93 return function_name
+ async_end
;
100 * \brief Search and replace "_args" substring in struct name if exist (for C# class naming)
102 * \return Modified struct name ("Struct_args" -> "StructArgs") or original name
104 static string
check_and_correct_struct_name(const string
& struct_name
)
106 string args_end
= "_args";
107 size_t i
= struct_name
.find(args_end
);
108 if (i
!= string::npos
)
110 string new_struct_name
= struct_name
;
111 new_struct_name
.replace(i
, args_end
.length(), "Args");
112 return new_struct_name
;
115 string result_end
= "_result";
116 size_t j
= struct_name
.find(result_end
);
117 if (j
!= string::npos
)
119 string new_struct_name
= struct_name
;
120 new_struct_name
.replace(j
, result_end
.length(), "Result");
121 return new_struct_name
;
127 static bool field_has_default(t_field
* tfield
) { return tfield
->get_value() != NULL
; }
129 static bool field_is_required(t_field
* tfield
) { return tfield
->get_req() == t_field::T_REQUIRED
; }
131 static bool type_can_be_null(t_type
* ttype
)
133 while (ttype
->is_typedef())
135 ttype
= static_cast<t_typedef
*>(ttype
)->get_type();
138 return ttype
->is_container() || ttype
->is_struct() || ttype
->is_xception() || ttype
->is_string();
141 bool t_netstd_generator::is_wcf_enabled() const { return wcf_
; }
143 bool t_netstd_generator::is_serialize_enabled() const { return serialize_
; }
145 bool t_netstd_generator::is_union_enabled() const { return union_
; }
147 map
<string
, int> t_netstd_generator::get_keywords_list() const
149 return netstd_keywords
;
152 void t_netstd_generator::init_generator()
154 MKDIR(get_out_dir().c_str());
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())
160 namespace_name_
= program_
->get_namespace("netstd");
163 string dir
= namespace_name_
;
164 string subdir
= get_out_dir().c_str();
165 string::size_type loc
;
167 while ((loc
= dir
.find(".")) != string::npos
)
169 subdir
= subdir
+ "/" + dir
.substr(0, loc
);
170 MKDIR(subdir
.c_str());
171 dir
= dir
.substr(loc
+ 1);
175 subdir
= subdir
+ "/" + dir
;
176 MKDIR(subdir
.c_str());
179 namespace_dir_
= subdir
;
182 while (!member_mapping_scopes
.empty())
184 cleanup_member_name_mapping(member_mapping_scopes
.back().scope_member
);
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"));
193 string
t_netstd_generator::normalize_name(string name
)
196 transform(tmp
.begin(), tmp
.end(), tmp
.begin(), static_cast<int(*)(int)>(tolower
));
198 // un-conflict keywords by prefixing with "@"
199 if (netstd_keywords
.find(tmp
) != netstd_keywords
.end())
204 // no changes necessary
208 void t_netstd_generator::init_keywords()
210 netstd_keywords
.clear();
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;
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;
316 netstd_keywords
["when"] = 1;
319 void t_netstd_generator::start_netstd_namespace(ostream
& out
)
321 if (!namespace_name_
.empty())
323 out
<< "namespace " << namespace_name_
<< endl
;
328 void t_netstd_generator::end_netstd_namespace(ostream
& out
)
330 if (!namespace_name_
.empty())
336 string
t_netstd_generator::netstd_type_usings() const
340 "using System.Collections;\n"
341 "using System.Collections.Generic;\n"
342 "using System.Text;\n"
344 "using System.Threading;\n"
345 "using System.Threading.Tasks;\n"
347 "using Thrift.Collections;\n";
349 if (is_wcf_enabled())
351 namespaces
+= "using System.ServiceModel;\n";
352 namespaces
+= "using System.Runtime.Serialization;\n";
355 return namespaces
+ endl
;
358 string
t_netstd_generator::netstd_thrift_usings() const
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";
369 return namespaces
+ endl
;
372 void t_netstd_generator::close_generator()
376 void t_netstd_generator::generate_typedef(t_typedef
* ttypedef
)
381 void t_netstd_generator::generate_enum(t_enum
* tenum
)
383 int ic
= indent_count();
384 string f_enum_name
= namespace_dir_
+ "/" + tenum
->get_name() + ".cs";
386 ofstream_with_content_based_conditional_update f_enum
;
387 f_enum
.open(f_enum_name
.c_str());
389 generate_enum(f_enum
, tenum
);
392 indent_validate(ic
, "generate_enum");
395 void t_netstd_generator::generate_enum(ostream
& out
, t_enum
* tenum
)
397 out
<< autogen_comment() << endl
;
399 start_netstd_namespace(out
);
400 generate_netstd_doc(out
, tenum
);
402 out
<< indent() << "public enum " << tenum
->get_name() << endl
;
405 vector
<t_enum_value
*> constants
= tenum
->get_constants();
406 vector
<t_enum_value
*>::iterator c_iter
;
408 for (c_iter
= constants
.begin(); c_iter
!= constants
.end(); ++c_iter
)
410 generate_netstd_doc(out
, *c_iter
);
411 int value
= (*c_iter
)->get_value();
412 out
<< indent() << (*c_iter
)->get_name() << " = " << value
<< "," << endl
;
416 end_netstd_namespace(out
);
419 void t_netstd_generator::generate_consts(vector
<t_const
*> consts
)
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());
430 generate_consts(f_consts
, consts
);
435 void t_netstd_generator::generate_consts(ostream
& out
, vector
<t_const
*> consts
)
442 out
<< autogen_comment() << netstd_type_usings() << endl
;
444 start_netstd_namespace(out
);
446 out
<< indent() << "public static class " << make_valid_csharp_identifier(program_name_
) << "Constants" << endl
;
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
)
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))
457 need_static_constructor
= true;
461 if (need_static_constructor
)
463 print_const_constructor(out
, consts
);
467 end_netstd_namespace(out
);
470 void t_netstd_generator::print_const_def_value(ostream
& out
, string name
, t_type
* type
, t_const_value
* value
)
472 if (type
->is_struct() || type
->is_xception())
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
));
480 for (v_iter
= val
.begin(); v_iter
!= val
.end(); ++v_iter
)
482 t_field
* field
= NULL
;
484 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
)
486 if ((*f_iter
)->get_name() == v_iter
->first
->get_string())
494 throw "type error: " + type
->get_name() + " has no field " + v_iter
->first
->get_string();
497 t_type
* field_type
= field
->get_type();
499 string val
= render_const_value(out
, name
, field_type
, v_iter
->second
);
500 out
<< indent() << name
<< "." << prop_name(field
) << " = " << val
<< ";" << endl
;
503 cleanup_member_name_mapping(static_cast<t_struct
*>(type
));
505 else if (type
->is_map())
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
)
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
;
518 else if (type
->is_list() || type
->is_set())
523 etype
= static_cast<t_list
*>(type
)->get_elem_type();
527 etype
= static_cast<t_set
*>(type
)->get_elem_type();
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
)
534 string val
= render_const_value(out
, name
, etype
, *v_iter
);
535 out
<< indent() << name
<< ".Add(" << val
<< ");" << endl
;
540 void t_netstd_generator::print_const_constructor(ostream
& out
, vector
<t_const
*> consts
)
542 out
<< indent() << "static " << make_valid_csharp_identifier(program_name_
).c_str() << "Constants()" << endl
;
545 vector
<t_const
*>::iterator c_iter
;
546 for (c_iter
= consts
.begin(); c_iter
!= consts
.end(); ++c_iter
)
548 string name
= (*c_iter
)->get_name();
549 t_type
* type
= (*c_iter
)->get_type();
550 t_const_value
* value
= (*c_iter
)->get_value();
552 print_const_def_value(out
, name
, type
, value
);
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
)
560 bool need_static_construction
= !in_static
;
561 while (type
->is_typedef())
563 type
= static_cast<t_typedef
*>(type
)->get_type();
566 if (!defval
|| needtype
)
568 out
<< (in_static
? "" : type
->is_base_type() ? "public const " : "public static ") << type_name(type
) << " ";
571 if (type
->is_base_type())
573 string v2
= render_const_value(out
, name
, type
, value
);
574 out
<< normalize_name(name
) << " = " << v2
<< ";" << endl
;
575 need_static_construction
= false;
577 else if (type
->is_enum())
579 out
<< name
<< " = " << type_name(type
) << "." << value
->get_identifier_name() << ";" << endl
;
580 need_static_construction
= false;
582 else if (type
->is_struct() || type
->is_xception())
584 out
<< name
<< " = new " << type_name(type
) << "();" << endl
;
586 else if (type
->is_map())
588 out
<< name
<< " = new " << type_name(type
) << "();" << endl
;
590 else if (type
->is_list() || type
->is_set())
592 out
<< name
<< " = new " << type_name(type
) << "();" << endl
;
595 if (defval
&& !type
->is_base_type() && !type
->is_enum())
597 print_const_def_value(out
, name
, type
, value
);
600 return need_static_construction
;
603 string
t_netstd_generator::render_const_value(ostream
& out
, string name
, t_type
* type
, t_const_value
* value
)
606 ostringstream render
;
608 if (type
->is_base_type())
610 t_base_type::t_base tbase
= static_cast<t_base_type
*>(type
)->get_base();
613 case t_base_type::TYPE_STRING
:
614 render
<< '"' << get_escaped_string(value
) << '"';
616 case t_base_type::TYPE_BOOL
:
617 render
<< ((value
->get_integer() > 0) ? "true" : "false");
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();
625 case t_base_type::TYPE_DOUBLE
:
626 if (value
->get_type() == t_const_value::CV_INTEGER
)
628 render
<< value
->get_integer();
632 render
<< value
->get_double();
636 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase
);
639 else if (type
->is_enum())
641 render
<< type
->get_name() << "." << value
->get_identifier_name();
645 string t
= tmp("tmp");
646 print_const_value(out
, t
, type
, value
, true, true, true);
653 void t_netstd_generator::generate_struct(t_struct
* tstruct
)
655 if (is_union_enabled() && tstruct
->is_union())
657 generate_netstd_union(tstruct
);
661 generate_netstd_struct(tstruct
, false);
665 void t_netstd_generator::generate_xception(t_struct
* txception
)
667 generate_netstd_struct(txception
, true);
670 void t_netstd_generator::generate_netstd_struct(t_struct
* tstruct
, bool is_exception
)
672 int ic
= indent_count();
674 string f_struct_name
= namespace_dir_
+ "/" + (tstruct
->get_name()) + ".cs";
675 ofstream_with_content_based_conditional_update f_struct
;
677 f_struct
.open(f_struct_name
.c_str());
679 f_struct
<< autogen_comment() << netstd_type_usings() << netstd_thrift_usings() << endl
;
681 generate_netstd_struct_definition(f_struct
, tstruct
, is_exception
);
685 indent_validate(ic
, "generate_netstd_struct");
688 void t_netstd_generator::generate_netstd_struct_definition(ostream
& out
, t_struct
* tstruct
, bool is_exception
, bool in_class
, bool is_result
)
692 start_netstd_namespace(out
);
697 generate_netstd_doc(out
, tstruct
);
698 prepare_member_name_mapping(tstruct
);
700 if ((is_serialize_enabled() || is_wcf_enabled()) && !is_exception
)
702 out
<< indent() << "[DataContract(Namespace=\"" << wcf_namespace_
<< "\")]" << endl
;
705 bool is_final
= tstruct
->annotations_
.find("final") != tstruct
->annotations_
.end();
707 string sharp_struct_name
= check_and_correct_struct_name(normalize_name(tstruct
->get_name()));
709 out
<< indent() << "public " << (is_final
? "sealed " : "") << "partial class " << sharp_struct_name
<< " : ";
713 out
<< "TException, ";
716 out
<< "TBase" << endl
717 << indent() << "{" << endl
;
720 const vector
<t_field
*>& members
= tstruct
->get_members();
721 vector
<t_field
*>::const_iterator m_iter
;
723 // make private members with public Properties
724 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
)
726 // if the field is required, then we use auto-properties
727 if (!field_is_required((*m_iter
)))
729 out
<< indent() << "private " << declare_field(*m_iter
, false, "_") << endl
;
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
)
738 generate_netstd_doc(out
, *m_iter
);
739 generate_property(out
, *m_iter
, true, true);
740 bool is_required
= field_is_required((*m_iter
));
743 has_required_fields
= true;
747 has_non_required_fields
= true;
751 bool generate_isset
= has_non_required_fields
;
755 if (is_serialize_enabled() || is_wcf_enabled())
757 out
<< indent() << "[DataMember(Order = 1)]" << endl
;
759 out
<< indent() << "public Isset __isset;" << endl
;
760 if (is_serialize_enabled() || is_wcf_enabled())
762 out
<< indent() << "[DataContract]" << endl
;
765 out
<< indent() << "public struct Isset" << endl
766 << indent() << "{" << endl
;
769 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
)
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
776 if (is_serialize_enabled() || is_wcf_enabled())
778 out
<< indent() << "[DataMember]" << endl
;
780 out
<< indent() << "public bool " << normalize_name((*m_iter
)->get_name()) << ";" << endl
;
785 out
<< indent() << "}" << endl
<< endl
;
787 if (generate_isset
&& (is_serialize_enabled() || is_wcf_enabled()))
789 out
<< indent() << "#region XmlSerializer support" << endl
<< endl
;
791 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
)
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
798 out
<< indent() << "public bool ShouldSerialize" << prop_name(*m_iter
) << "()" << endl
799 << indent() << "{" << endl
;
801 out
<< indent() << "return __isset." << normalize_name((*m_iter
)->get_name()) << ";" << endl
;
803 out
<< indent() << "}" << endl
<< endl
;
807 out
<< indent() << "#endregion XmlSerializer support" << endl
<< endl
;
811 // We always want a default, no argument constructor for Reading
812 out
<< indent() << "public " << sharp_struct_name
<< "()" << endl
813 << indent() << "{" << endl
;
816 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
)
818 t_type
* t
= (*m_iter
)->get_type();
819 while (t
->is_typedef())
821 t
= static_cast<t_typedef
*>(t
)->get_type();
823 if ((*m_iter
)->get_value() != NULL
)
825 if (field_is_required((*m_iter
)))
827 print_const_value(out
, "this." + prop_name(*m_iter
), t
, (*m_iter
)->get_value(), true, true);
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
;
838 out
<< indent() << "}" << endl
<< endl
;
840 if (has_required_fields
)
842 out
<< indent() << "public " << sharp_struct_name
<< "(";
844 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
)
846 if (field_is_required(*m_iter
))
856 out
<< type_name((*m_iter
)->get_type()) << " " << (*m_iter
)->get_name();
859 out
<< ") : this()" << endl
860 << indent() << "{" << endl
;
863 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
)
865 if (field_is_required(*m_iter
))
867 out
<< indent() << "this." << prop_name(*m_iter
) << " = " << (*m_iter
)->get_name() << ";" << endl
;
872 out
<< indent() << "}" << endl
<< endl
;
875 generate_netstd_struct_reader(out
, tstruct
);
878 generate_netstd_struct_result_writer(out
, tstruct
);
882 generate_netstd_struct_writer(out
, tstruct
);
884 generate_netstd_struct_equals(out
, tstruct
);
885 generate_netstd_struct_hashcode(out
, tstruct
);
886 generate_netstd_struct_tostring(out
, tstruct
);
889 out
<< indent() << "}" << endl
<< endl
;
891 // generate a corresponding WCF fault to wrap the exception
892 if ((is_serialize_enabled() || is_wcf_enabled()) && is_exception
)
894 generate_netstd_wcffault(out
, tstruct
);
897 cleanup_member_name_mapping(tstruct
);
900 end_netstd_namespace(out
);
904 void t_netstd_generator::generate_netstd_wcffault(ostream
& out
, t_struct
* tstruct
)
907 out
<< indent() << "[DataContract]" << endl
;
909 bool is_final
= tstruct
->annotations_
.find("final") != tstruct
->annotations_
.end();
911 out
<< indent() << "public " << (is_final
? "sealed " : "") << "partial class " << tstruct
->get_name() << "Fault" << endl
912 << indent() << "{" << endl
;
915 const vector
<t_field
*>& members
= tstruct
->get_members();
916 vector
<t_field
*>::const_iterator m_iter
;
918 // make private members with public Properties
919 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
)
921 // if the field is required, then we use auto-properties
922 if (!field_is_required((*m_iter
)))
924 out
<< indent() << "private " << declare_field(*m_iter
, false, "_") << endl
;
929 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
)
931 generate_property(out
, *m_iter
, true, false);
935 out
<< indent() << "}" << endl
<< endl
;
938 void t_netstd_generator::generate_netstd_struct_reader(ostream
& out
, t_struct
* tstruct
)
940 out
<< indent() << "public async Task ReadAsync(TProtocol iprot, CancellationToken cancellationToken)" << endl
941 << indent() << "{" << endl
;
943 out
<< indent() << "iprot.IncrementRecursionDepth();" << endl
944 << indent() << "try" << endl
945 << indent() << "{" << endl
;
948 const vector
<t_field
*>& fields
= tstruct
->get_members();
949 vector
<t_field
*>::const_iterator f_iter
;
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
)
954 if (field_is_required(*f_iter
))
956 out
<< indent() << "bool isset_" << (*f_iter
)->get_name() << " = false;" << endl
;
960 out
<< indent() << "TField field;" << endl
961 << indent() << "await iprot.ReadStructBeginAsync(cancellationToken);" << endl
962 << indent() << "while (true)" << endl
963 << indent() << "{" << endl
;
965 out
<< indent() << "field = await iprot.ReadFieldBeginAsync(cancellationToken);" << endl
966 << indent() << "if (field.Type == TType.Stop)" << endl
967 << indent() << "{" << endl
;
969 out
<< indent() << "break;" << endl
;
971 out
<< indent() << "}" << endl
<< endl
972 << indent() << "switch (field.ID)" << endl
973 << indent() << "{" << endl
;
976 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
)
978 bool is_required
= field_is_required(*f_iter
);
979 out
<< indent() << "case " << (*f_iter
)->get_key() << ":" << endl
;
981 out
<< indent() << "if (field.Type == " << type_to_enum((*f_iter
)->get_type()) << ")" << endl
982 << indent() << "{" << endl
;
985 generate_deserialize_field(out
, *f_iter
);
988 out
<< indent() << "isset_" << (*f_iter
)->get_name() << " = true;" << endl
;
992 out
<< indent() << "}" << endl
993 << indent() << "else" << endl
994 << indent() << "{" << endl
;
996 out
<< indent() << "await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);" << endl
;
998 out
<< indent() << "}" << endl
999 << indent() << "break;" << endl
;
1003 out
<< indent() << "default: " << endl
;
1005 out
<< indent() << "await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);" << endl
1006 << indent() << "break;" << endl
;
1009 out
<< indent() << "}" << endl
1011 << indent() << "await iprot.ReadFieldEndAsync(cancellationToken);" << endl
;
1013 out
<< indent() << "}" << endl
1015 << indent() << "await iprot.ReadStructEndAsync(cancellationToken);" << endl
;
1017 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
)
1019 if (field_is_required((*f_iter
)))
1021 out
<< indent() << "if (!isset_" << (*f_iter
)->get_name() << ")" << endl
1022 << indent() << "{" << endl
;
1024 out
<< indent() << "throw new TProtocolException(TProtocolException.INVALID_DATA);" << endl
;
1026 out
<< indent() << "}" << endl
;
1031 out
<< indent() << "}" << endl
;
1032 out
<< indent() << "finally" << endl
1033 << indent() << "{" << endl
;
1035 out
<< indent() << "iprot.DecrementRecursionDepth();" << endl
;
1037 out
<< indent() << "}" << endl
;
1039 out
<< indent() << "}" << endl
<< endl
;
1042 void t_netstd_generator::generate_netstd_struct_writer(ostream
& out
, t_struct
* tstruct
)
1044 out
<< indent() << "public async Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken)" << endl
1045 << indent() << "{" << endl
;
1048 out
<< indent() << "oprot.IncrementRecursionDepth();" << endl
1049 << indent() << "try" << endl
1050 << indent() << "{" << endl
;
1053 string name
= tstruct
->get_name();
1054 const vector
<t_field
*>& fields
= tstruct
->get_sorted_members();
1055 vector
<t_field
*>::const_iterator f_iter
;
1057 out
<< indent() << "var struc = new TStruct(\"" << name
<< "\");" << endl
1058 << indent() << "await oprot.WriteStructBeginAsync(struc, cancellationToken);" << endl
;
1060 if (fields
.size() > 0)
1062 out
<< indent() << "var field = new TField();" << endl
;
1063 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
)
1065 bool is_required
= field_is_required(*f_iter
);
1068 bool null_allowed
= type_can_be_null((*f_iter
)->get_type());
1071 out
<< indent() << "if (" << prop_name(*f_iter
) << " != null && __isset." << normalize_name((*f_iter
)->get_name()) << ")" << endl
1072 << indent() << "{" << endl
;
1077 out
<< indent() << "if (__isset." << normalize_name((*f_iter
)->get_name()) << ")" << endl
1078 << indent() << "{" << endl
;
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
;
1087 generate_serialize_field(out
, *f_iter
);
1089 out
<< indent() << "await oprot.WriteFieldEndAsync(cancellationToken);" << endl
;
1093 out
<< indent() << "}" << endl
;
1098 out
<< indent() << "await oprot.WriteFieldStopAsync(cancellationToken);" << endl
1099 << indent() << "await oprot.WriteStructEndAsync(cancellationToken);" << endl
;
1101 out
<< indent() << "}" << endl
1102 << indent() << "finally" << endl
1103 << indent() << "{" << endl
;
1105 out
<< indent() << "oprot.DecrementRecursionDepth();" << endl
;
1107 out
<< indent() << "}" << endl
;
1109 out
<< indent() << "}" << endl
<< endl
;
1112 void t_netstd_generator::generate_netstd_struct_result_writer(ostream
& out
, t_struct
* tstruct
)
1114 out
<< indent() << "public async Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken)" << endl
1115 << indent() << "{" << endl
;
1118 out
<< indent() << "oprot.IncrementRecursionDepth();" << endl
1119 << indent() << "try" << endl
1120 << indent() << "{" << endl
;
1123 string name
= tstruct
->get_name();
1124 const vector
<t_field
*>& fields
= tstruct
->get_sorted_members();
1125 vector
<t_field
*>::const_iterator f_iter
;
1127 out
<< indent() << "var struc = new TStruct(\"" << name
<< "\");" << endl
1128 << indent() << "await oprot.WriteStructBeginAsync(struc, cancellationToken);" << endl
;
1130 if (fields
.size() > 0)
1132 out
<< indent() << "var field = new TField();" << endl
;
1134 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
)
1139 out
<< endl
<< indent() << "if";
1143 out
<< indent() << "else if";
1146 out
<< "(this.__isset." << normalize_name((*f_iter
)->get_name()) << ")" << endl
1147 << indent() << "{" << endl
;
1150 bool null_allowed
= type_can_be_null((*f_iter
)->get_type());
1153 out
<< indent() << "if (" << prop_name(*f_iter
) << " != null)" << endl
1154 << indent() << "{" << endl
;
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
;
1163 generate_serialize_field(out
, *f_iter
);
1165 out
<< indent() << "await oprot.WriteFieldEndAsync(cancellationToken);" << endl
;
1170 out
<< indent() << "}" << endl
;
1174 out
<< indent() << "}" << endl
;
1178 out
<< indent() << "await oprot.WriteFieldStopAsync(cancellationToken);" << endl
1179 << indent() << "await oprot.WriteStructEndAsync(cancellationToken);" << endl
;
1181 out
<< indent() << "}" << endl
1182 << indent() << "finally" << endl
1183 << indent() << "{" << endl
;
1185 out
<< indent() << "oprot.DecrementRecursionDepth();" << endl
;
1187 out
<< indent() << "}" << endl
;
1189 out
<< indent() << "}" << endl
<< endl
;
1192 void t_netstd_generator::generate_netstd_struct_tostring(ostream
& out
, t_struct
* tstruct
)
1194 out
<< indent() << "public override string ToString()" << endl
1195 << indent() << "{" << endl
;
1197 out
<< indent() << "var sb = new StringBuilder(\"" << tstruct
->get_name() << "(\");" << endl
;
1199 const vector
<t_field
*>& fields
= tstruct
->get_members();
1200 vector
<t_field
*>::const_iterator f_iter
;
1202 bool useFirstFlag
= false;
1203 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
)
1205 if (!field_is_required((*f_iter
)))
1207 out
<< indent() << "bool __first = true;" << endl
;
1208 useFirstFlag
= true;
1213 bool had_required
= false; // set to true after first required field has been processed
1215 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
)
1217 bool is_required
= field_is_required((*f_iter
));
1220 bool null_allowed
= type_can_be_null((*f_iter
)->get_type());
1223 out
<< indent() << "if (" << prop_name((*f_iter
)) << " != null && __isset." << normalize_name((*f_iter
)->get_name()) << ")" << endl
1224 << indent() << "{" << endl
;
1229 out
<< indent() << "if (__isset." << normalize_name((*f_iter
)->get_name()) << ")" << endl
1230 << indent() << "{" << endl
;
1235 if (useFirstFlag
&& (!had_required
))
1237 out
<< indent() << "if(!__first) { sb.Append(\", \"); }" << endl
;
1240 out
<< indent() << "__first = false;" << endl
;
1242 out
<< indent() << "sb.Append(\"" << prop_name(*f_iter
) << ": \");" << endl
;
1246 out
<< indent() << "sb.Append(\", " << prop_name(*f_iter
) << ": \");" << endl
;
1249 t_type
* ttype
= (*f_iter
)->get_type();
1250 if (ttype
->is_xception() || ttype
->is_struct())
1252 out
<< indent() << "sb.Append(" << prop_name(*f_iter
) << "== null ? \"<null>\" : " << prop_name(*f_iter
) << ".ToString());" << endl
;
1256 out
<< indent() << "sb.Append(" << prop_name(*f_iter
) << ");" << endl
;
1262 out
<< indent() << "}" << endl
;
1266 had_required
= true; // now __first must be false, so we don't need to check it anymore
1270 out
<< indent() << "sb.Append(\")\");" << endl
1271 << indent() << "return sb.ToString();" << endl
;
1273 out
<< indent() << "}" << endl
;
1276 void t_netstd_generator::generate_netstd_union(t_struct
* tunion
)
1278 int ic
= indent_count();
1280 string f_union_name
= namespace_dir_
+ "/" + (tunion
->get_name()) + ".cs";
1281 ofstream_with_content_based_conditional_update f_union
;
1283 f_union
.open(f_union_name
.c_str());
1285 f_union
<< autogen_comment() << netstd_type_usings() << netstd_thrift_usings() << endl
;
1287 generate_netstd_union_definition(f_union
, tunion
);
1291 indent_validate(ic
, "generate_netstd_union.");
1294 void t_netstd_generator::generate_netstd_union_definition(ostream
& out
, t_struct
* tunion
)
1296 // Let's define the class first
1297 start_netstd_namespace(out
);
1299 out
<< indent() << "public abstract partial class " << tunion
->get_name() << " : TUnionBase" << endl
1300 << indent() << "{" << endl
;
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
;
1309 out
<< indent() << "Isset = isset;" << endl
;
1311 out
<< indent() << "}" << endl
<< endl
;
1313 out
<< indent() << "public class ___undefined : " << tunion
->get_name() << endl
1314 << indent() << "{" << endl
;
1317 out
<< indent() << "public override object Data { get { return null; } }" << endl
1318 << indent() << "public ___undefined() : base(0) {}" << endl
<< endl
;
1320 out
<< indent() << "public override Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken)" << endl
1321 << indent() << "{" << endl
;
1323 out
<< indent() << "throw new TProtocolException( TProtocolException.INVALID_DATA, \"Cannot persist an union type which is not set.\");" << endl
;
1325 out
<< indent() << "}" << endl
<< endl
;
1327 out
<< indent() << "}" << endl
<< endl
;
1329 const vector
<t_field
*>& fields
= tunion
->get_members();
1330 vector
<t_field
*>::const_iterator f_iter
;
1332 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
)
1334 generate_netstd_union_class(out
, tunion
, (*f_iter
));
1337 generate_netstd_union_reader(out
, tunion
);
1340 out
<< indent() << "}" << endl
<< endl
;
1342 end_netstd_namespace(out
);
1345 void t_netstd_generator::generate_netstd_union_class(ostream
& out
, t_struct
* tunion
, t_field
* tfield
)
1347 out
<< indent() << "public " << type_name(tfield
->get_type()) << " As_" << tfield
->get_name() << endl
;
1348 out
<< indent() << "{" << endl
;
1350 out
<< indent() << "get" << endl
;
1351 out
<< indent() << "{" << endl
;
1353 out
<< indent() << "return (" << tfield
->get_key() << " == Isset) ? (" << type_name(tfield
->get_type()) << ")Data : default(" << type_name(tfield
->get_type()) << ");" << endl
;
1355 out
<< indent() << "}" << endl
;
1357 out
<< indent() << "}" << endl
1361 out
<< indent() << "public class " << tfield
->get_name() << " : " << tunion
->get_name() << endl
1362 << indent() << "{" << endl
;
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
;
1370 out
<< indent() << "this._data = data;" << endl
;
1372 out
<< indent() << "}" << endl
;
1374 out
<< indent() << "public override async Task WriteAsync(TProtocol oprot, CancellationToken cancellationToken) {" << endl
;
1377 out
<< indent() << "oprot.IncrementRecursionDepth();" << endl
1378 << indent() << "try" << endl
1379 << indent() << "{" << endl
;
1382 out
<< indent() << "var struc = new TStruct(\"" << tunion
->get_name() << "\");" << endl
1383 << indent() << "await oprot.WriteStructBeginAsync(struc, cancellationToken);" << endl
;
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
;
1391 generate_serialize_field(out
, tfield
, "_data", true);
1393 out
<< indent() << "await oprot.WriteFieldEndAsync(cancellationToken);" << endl
1394 << indent() << "await oprot.WriteFieldStopAsync(cancellationToken);" << endl
1395 << indent() << "await oprot.WriteStructEndAsync(cancellationToken);" << endl
;
1397 out
<< indent() << "}" << endl
1398 << indent() << "finally" << endl
1399 << indent() << "{" << endl
;
1401 out
<< indent() << "oprot.DecrementRecursionDepth();" << endl
;
1403 out
<< indent() << "}" << endl
;
1404 out
<< indent() << "}" << endl
;
1406 out
<< indent() << "}" << endl
<< endl
;
1409 void t_netstd_generator::generate_netstd_struct_equals(ostream
& out
, t_struct
* tstruct
)
1411 out
<< indent() << "public override bool Equals(object that)" << endl
1412 << indent() << "{" << endl
;
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
;
1418 const vector
<t_field
*>& fields
= tstruct
->get_members();
1419 vector
<t_field
*>::const_iterator f_iter
;
1423 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
)
1428 out
<< indent() << "return ";
1434 out
<< indent() << "&& ";
1436 if (!field_is_required((*f_iter
)))
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()) << ") || (";
1442 t_type
* ttype
= (*f_iter
)->get_type();
1443 if (ttype
->is_container() || ttype
->is_binary())
1445 out
<< "TCollections.Equals(";
1449 out
<< "System.Object.Equals(";
1451 out
<< prop_name((*f_iter
)) << ", other." << prop_name((*f_iter
)) << ")";
1452 if (!field_is_required((*f_iter
)))
1459 out
<< indent() << "return true;" << endl
;
1468 out
<< indent() << "}" << endl
<< endl
;
1471 void t_netstd_generator::generate_netstd_struct_hashcode(ostream
& out
, t_struct
* tstruct
)
1473 out
<< indent() << "public override int GetHashCode() {" << endl
;
1476 out
<< indent() << "int hashcode = 157;" << endl
;
1477 out
<< indent() << "unchecked {" << endl
;
1480 const vector
<t_field
*>& fields
= tstruct
->get_members();
1481 vector
<t_field
*>::const_iterator f_iter
;
1483 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
)
1485 t_type
* ttype
= (*f_iter
)->get_type();
1486 if (!field_is_required((*f_iter
)))
1488 out
<< indent() << "if(__isset." << normalize_name((*f_iter
)->get_name()) << ")" << endl
;
1491 out
<< indent() << "hashcode = (hashcode * 397) + ";
1492 if (ttype
->is_container())
1494 out
<< "TCollections.GetHashCode(" << prop_name((*f_iter
)) << ")";
1498 out
<< prop_name((*f_iter
)) << ".GetHashCode()";
1502 if (!field_is_required((*f_iter
)))
1509 out
<< indent() << "}" << endl
;
1510 out
<< indent() << "return hashcode;" << endl
;
1513 out
<< indent() << "}" << endl
<< endl
;
1516 void t_netstd_generator::generate_service(t_service
* tservice
)
1518 int ic
= indent_count();
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());
1524 f_service
<< autogen_comment() << netstd_type_usings() << netstd_thrift_usings() << endl
;
1526 start_netstd_namespace(f_service
);
1528 f_service
<< indent() << "public partial class " << normalize_name(service_name_
) << endl
1529 << indent() << "{" << endl
;
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
);
1538 f_service
<< indent() << "}" << endl
;
1540 end_netstd_namespace(f_service
);
1543 indent_validate(ic
, "generate_service.");
1546 void t_netstd_generator::generate_service_interface(ostream
& out
, t_service
* tservice
)
1548 string extends
= "";
1549 string extends_iface
= "";
1550 if (tservice
->get_extends() != NULL
)
1552 extends
= type_name(tservice
->get_extends());
1553 extends_iface
= " : " + extends
+ ".IAsync";
1556 //out << endl << endl;
1558 generate_netstd_doc(out
, tservice
);
1560 if (is_wcf_enabled())
1562 out
<< indent() << "[ServiceContract(Namespace=\"" << wcf_namespace_
<< "\")]" << endl
;
1565 out
<< indent() << "public interface IAsync" << extends_iface
<< endl
1566 << indent() << "{" << endl
;
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
)
1573 generate_netstd_doc(out
, *f_iter
);
1575 // if we're using WCF, add the corresponding attributes
1576 if (is_wcf_enabled())
1578 out
<< indent() << "[OperationContract]" << endl
;
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
)
1584 out
<< indent() << "[FaultContract(typeof(" + type_name((*x_iter
)->get_type()) + "Fault))]" << endl
;
1588 out
<< indent() << function_signature_async(*f_iter
) << ";" << endl
<< endl
;
1591 out
<< indent() << "}" << endl
<< endl
;
1594 void t_netstd_generator::generate_service_helpers(ostream
& out
, t_service
* tservice
)
1596 vector
<t_function
*> functions
= tservice
->get_functions();
1597 vector
<t_function
*>::iterator f_iter
;
1599 for (f_iter
= functions
.begin(); f_iter
!= functions
.end(); ++f_iter
)
1601 t_struct
* ts
= (*f_iter
)->get_arglist();
1602 generate_netstd_struct_definition(out
, ts
, false, true);
1603 generate_function_helpers(out
, *f_iter
);
1607 void t_netstd_generator::generate_service_client(ostream
& out
, t_service
* tservice
)
1609 string extends
= "";
1610 string extends_client
= "";
1611 if (tservice
->get_extends() != NULL
)
1613 extends
= type_name(tservice
->get_extends());
1614 extends_client
= extends
+ ".Client, ";
1618 extends_client
= "TBaseClient, IDisposable, ";
1623 generate_netstd_doc(out
, tservice
);
1625 out
<< indent() << "public class Client : " << extends_client
<< "IAsync" << endl
1626 << indent() << "{" << endl
;
1629 out
<< indent() << "public Client(TProtocol protocol) : this(protocol, protocol)" << endl
1630 << indent() << "{" << endl
1631 << indent() << "}" << endl
1633 << indent() << "public Client(TProtocol inputProtocol, TProtocol outputProtocol) : base(inputProtocol, outputProtocol)"
1634 << indent() << "{" << endl
1635 << indent() << "}" << endl
;
1637 vector
<t_function
*> functions
= tservice
->get_functions();
1638 vector
<t_function
*>::const_iterator functions_iterator
;
1640 for (functions_iterator
= functions
.begin(); functions_iterator
!= functions
.end(); ++functions_iterator
)
1642 string function_name
= correct_function_name_for_async((*functions_iterator
)->get_name());
1645 out
<< indent() << "public async " << function_signature_async(*functions_iterator
, "") << endl
1646 << indent() << "{" << endl
;
1649 string argsname
= (*functions_iterator
)->get_name() + "Args";
1651 out
<< indent() << "await OutputProtocol.WriteMessageBeginAsync(new TMessage(\"" << function_name
1652 << "\", " << ((*functions_iterator
)->is_oneway() ? "TMessageType.Oneway" : "TMessageType.Call") << ", SeqId), cancellationToken);" << endl
1654 << indent() << "var args = new " << argsname
<< "();" << endl
;
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
;
1661 for (fld_iter
= fields
.begin(); fld_iter
!= fields
.end(); ++fld_iter
)
1663 out
<< indent() << "args." << prop_name(*fld_iter
) << " = " << normalize_name((*fld_iter
)->get_name()) << ";" << endl
;
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
;
1671 if (!(*functions_iterator
)->is_oneway())
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
);
1678 out
<< indent() << endl
1679 << indent() << "var msg = await InputProtocol.ReadMessageBeginAsync(cancellationToken);" << endl
1680 << indent() << "if (msg.Type == TMessageType.Exception)" << endl
1681 << indent() << "{" << endl
;
1684 out
<< indent() << "var x = await TApplicationException.ReadAsync(InputProtocol, cancellationToken);" << endl
1685 << indent() << "await InputProtocol.ReadMessageEndAsync(cancellationToken);" << endl
1686 << indent() << "throw x;" << endl
;
1689 out
<< indent() << "}" << endl
1691 << indent() << "var result = new " << resultname
<< "();" << endl
1692 << indent() << "await result.ReadAsync(InputProtocol, cancellationToken);" << endl
1693 << indent() << "await InputProtocol.ReadMessageEndAsync(cancellationToken);" << endl
;
1695 if (!(*functions_iterator
)->get_returntype()->is_void())
1697 out
<< indent() << "if (result.__isset.success)" << endl
1698 << indent() << "{" << endl
;
1700 out
<< indent() << "return result.Success;" << endl
;
1702 out
<< indent() << "}" << endl
;
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
)
1709 out
<< indent() << "if (result.__isset." << normalize_name((*x_iter
)->get_name()) << ")" << endl
1710 << indent() << "{" << endl
;
1712 out
<< indent() << "throw result." << prop_name(*x_iter
) << ";" << endl
;
1714 out
<< indent() << "}" << endl
;
1717 if ((*functions_iterator
)->get_returntype()->is_void())
1719 out
<< indent() << "return;" << endl
;
1723 out
<< indent() << "throw new TApplicationException(TApplicationException.ExceptionType.MissingResult, \""
1724 << function_name
<< " failed: unknown result\");" << endl
;
1727 cleanup_member_name_mapping((*functions_iterator
)->get_xceptions());
1729 out
<< indent() << "}" << endl
<< endl
;
1734 out
<< indent() << "}" << endl
;
1739 out
<< indent() << "}" << endl
<< endl
;
1742 void t_netstd_generator::generate_service_server(ostream
& out
, t_service
* tservice
)
1744 vector
<t_function
*> functions
= tservice
->get_functions();
1745 vector
<t_function
*>::iterator f_iter
;
1747 string extends
= "";
1748 string extends_processor
= "";
1749 if (tservice
->get_extends() != NULL
)
1751 extends
= type_name(tservice
->get_extends());
1752 extends_processor
= extends
+ ".AsyncProcessor, ";
1755 out
<< indent() << "public class AsyncProcessor : " << extends_processor
<< "ITAsyncProcessor" << endl
1756 << indent() << "{" << endl
;
1760 out
<< indent() << "private IAsync _iAsync;" << endl
1762 << indent() << "public AsyncProcessor(IAsync iAsync)";
1764 if (!extends
.empty())
1766 out
<< " : base(iAsync)";
1770 << indent() << "{" << endl
;
1773 out
<< indent() << "if (iAsync == null) throw new ArgumentNullException(nameof(iAsync));" << endl
1775 << indent() << "_iAsync = iAsync;" << endl
;
1777 for (f_iter
= functions
.begin(); f_iter
!= functions
.end(); ++f_iter
)
1779 string function_name
= (*f_iter
)->get_name();
1780 out
<< indent() << "processMap_[\"" << correct_function_name_for_async(function_name
) << "\"] = " << function_name
<< "_ProcessAsync;" << endl
;
1784 out
<< indent() << "}" << endl
1787 if (extends
.empty())
1789 out
<< indent() << "protected delegate Task ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken);" << endl
;
1792 if (extends
.empty())
1794 out
<< indent() << "protected Dictionary<string, ProcessFunction> processMap_ = new Dictionary<string, ProcessFunction>();" << endl
;
1799 if (extends
.empty())
1801 out
<< indent() << "public async Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot)" << endl
1802 << indent() << "{" << endl
;
1804 out
<< indent() << "return await ProcessAsync(iprot, oprot, CancellationToken.None);" << endl
;
1806 out
<< indent() << "}" << endl
<< endl
;
1808 out
<< indent() << "public async Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken)" << endl
;
1812 out
<< indent() << "public new async Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot)" << endl
1813 << indent() << "{" << endl
;
1815 out
<< indent() << "return await ProcessAsync(iprot, oprot, CancellationToken.None);" << endl
;
1817 out
<< indent() << "}" << endl
<< endl
;
1819 out
<< indent() << "public new async Task<bool> ProcessAsync(TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken)" << endl
;
1822 out
<< indent() << "{" << endl
;
1824 out
<< indent() << "try" << endl
1825 << indent() << "{" << endl
;
1827 out
<< indent() << "var msg = await iprot.ReadMessageBeginAsync(cancellationToken);" << endl
1829 << indent() << "ProcessFunction fn;" << endl
1830 << indent() << "processMap_.TryGetValue(msg.Name, out fn);" << endl
1832 << indent() << "if (fn == null)" << endl
1833 << indent() << "{" << endl
;
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
;
1844 out
<< indent() << "}" << endl
1846 << indent() << "await fn(msg.SeqID, iprot, oprot, cancellationToken);" << endl
1849 out
<< indent() << "}" << endl
;
1850 out
<< indent() << "catch (IOException)" << endl
1851 << indent() << "{" << endl
;
1853 out
<< indent() << "return false;" << endl
;
1855 out
<< indent() << "}" << endl
1857 << indent() << "return true;" << endl
;
1859 out
<< indent() << "}" << endl
<< endl
;
1861 for (f_iter
= functions
.begin(); f_iter
!= functions
.end(); ++f_iter
)
1863 generate_process_function_async(out
, tservice
, *f_iter
);
1867 out
<< indent() << "}" << endl
<< endl
;
1870 void t_netstd_generator::generate_function_helpers(ostream
& out
, t_function
* tfunction
)
1872 if (tfunction
->is_oneway())
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())
1881 result
.append(&success
);
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
)
1889 result
.append(*f_iter
);
1892 generate_netstd_struct_definition(out
, &result
, false, true, true);
1895 void t_netstd_generator::generate_process_function_async(ostream
& out
, t_service
* tservice
, t_function
* tfunction
)
1898 out
<< indent() << "public async Task " << tfunction
->get_name()
1899 << "_ProcessAsync(int seqid, TProtocol iprot, TProtocol oprot, CancellationToken cancellationToken)" << endl
1900 << indent() << "{" << endl
;
1903 string argsname
= tfunction
->get_name() + "Args";
1904 string resultname
= tfunction
->get_name() + "Result";
1906 out
<< indent() << "var args = new " << argsname
<< "();" << endl
1907 << indent() << "await args.ReadAsync(iprot, cancellationToken);" << endl
1908 << indent() << "await iprot.ReadMessageEndAsync(cancellationToken);" << endl
;
1910 if (!tfunction
->is_oneway())
1912 out
<< indent() << "var result = new " << resultname
<< "();" << endl
;
1915 out
<< indent() << "try" << endl
1916 << indent() << "{" << endl
;
1919 t_struct
* xs
= tfunction
->get_xceptions();
1920 const vector
<t_field
*>& xceptions
= xs
->get_members();
1922 if (xceptions
.size() > 0)
1924 out
<< indent() << "try" << endl
1925 << indent() << "{" << endl
;
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
;
1934 if (!tfunction
->is_oneway() && !tfunction
->get_returntype()->is_void())
1936 out
<< "result.Success = ";
1939 out
<< "await _iAsync." << normalize_name(tfunction
->get_name()) << "Async(";
1942 prepare_member_name_mapping(arg_struct
);
1943 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
)
1954 out
<< "args." << prop_name(*f_iter
);
1957 cleanup_member_name_mapping(arg_struct
);
1964 out
<< "cancellationToken);" << endl
;
1966 vector
<t_field
*>::const_iterator x_iter
;
1968 prepare_member_name_mapping(xs
, xs
->get_members(), resultname
);
1969 if (xceptions
.size() > 0)
1972 out
<< indent() << "}" << endl
;
1974 for (x_iter
= xceptions
.begin(); x_iter
!= xceptions
.end(); ++x_iter
)
1976 out
<< indent() << "catch (" << type_name((*x_iter
)->get_type()) << " " << (*x_iter
)->get_name() << ")" << endl
1977 << indent() << "{" << endl
;
1979 if (!tfunction
->is_oneway())
1982 out
<< indent() << "result." << prop_name(*x_iter
) << " = " << (*x_iter
)->get_name() << ";" << endl
;
1985 out
<< indent() << "}" << endl
;
1989 if (!tfunction
->is_oneway())
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
;
1997 cleanup_member_name_mapping(xs
);
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
;
2008 out
<< indent() << "Console.Error.WriteLine(\"Error occurred in processor:\");" << endl
2009 << indent() << "Console.Error.WriteLine(ex.ToString());" << endl
;
2011 if (tfunction
->is_oneway())
2014 out
<< indent() << "}" << endl
;
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
;
2024 out
<< indent() << "}" << endl
2025 << indent() << "await oprot.WriteMessageEndAsync(cancellationToken);" << endl
2026 << indent() << "await oprot.Transport.FlushAsync(cancellationToken);" << endl
;
2030 out
<< indent() << "}" << endl
<< endl
;
2033 void t_netstd_generator::generate_netstd_union_reader(ostream
& out
, t_struct
* tunion
)
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
;
2039 out
<< indent() << "public static async Task<" << tunion
->get_name() << "> ReadAsync(TProtocol iprot, CancellationToken cancellationToken)" << endl
;
2042 out
<< indent() << "iprot.IncrementRecursionDepth();" << endl
;
2043 out
<< indent() << "try" << endl
;
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
;
2052 out
<< indent() << "await iprot.ReadFieldEndAsync(cancellationToken);" << endl
;
2053 out
<< indent() << "retval = new ___undefined();" << endl
;
2055 out
<< indent() << "else" << endl
;
2057 out
<< indent() << "switch (field.ID)" << endl
;
2060 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
)
2062 out
<< indent() << "case " << (*f_iter
)->get_key() << ":" << endl
;
2064 out
<< indent() << "if (field.Type == " << type_to_enum((*f_iter
)->get_type()) << ") {" << endl
;
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
;
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
;
2078 out
<< indent() << "default: " << endl
;
2080 out
<< indent() << "await TProtocolUtil.SkipAsync(iprot, field.Type, cancellationToken);" << endl
<< indent()
2081 << "retval = new ___undefined();" << endl
;
2082 out
<< indent() << "break;" << endl
;
2087 out
<< indent() << "await iprot.ReadFieldEndAsync(cancellationToken);" << endl
;
2089 out
<< indent() << "if ((await iprot.ReadFieldBeginAsync(cancellationToken)).Type != TType.Stop)" << endl
;
2091 out
<< indent() << "throw new TProtocolException(TProtocolException.INVALID_DATA);" << endl
;
2094 // end of else for TStop
2096 out
<< indent() << "await iprot.ReadStructEndAsync(cancellationToken);" << endl
;
2097 out
<< indent() << "return retval;" << endl
;
2101 out
<< indent() << "finally" << endl
;
2103 out
<< indent() << "iprot.DecrementRecursionDepth();" << endl
;
2106 out
<< indent() << "}" << endl
<< endl
;
2109 void t_netstd_generator::generate_deserialize_field(ostream
& out
, t_field
* tfield
, string prefix
, bool is_propertyless
)
2111 t_type
* type
= tfield
->get_type();
2112 while (type
->is_typedef())
2114 type
= static_cast<t_typedef
*>(type
)->get_type();
2117 if (type
->is_void())
2119 throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix
+ tfield
->get_name();
2122 string name
= prefix
+ (is_propertyless
? "" : prop_name(tfield
));
2124 if (type
->is_struct() || type
->is_xception())
2126 generate_deserialize_struct(out
, static_cast<t_struct
*>(type
), name
);
2128 else if (type
->is_container())
2130 generate_deserialize_container(out
, type
, name
);
2132 else if (type
->is_base_type() || type
->is_enum())
2134 out
<< indent() << name
<< " = ";
2136 if (type
->is_enum())
2138 out
<< "(" << type_name(type
) << ")";
2141 out
<< "await iprot.";
2143 if (type
->is_base_type())
2145 t_base_type::t_base tbase
= static_cast<t_base_type
*>(type
)->get_base();
2148 case t_base_type::TYPE_VOID
:
2149 throw "compiler error: cannot serialize void field in a struct: " + name
;
2151 case t_base_type::TYPE_STRING
:
2152 if (type
->is_binary())
2154 out
<< "ReadBinaryAsync(cancellationToken);";
2158 out
<< "ReadStringAsync(cancellationToken);";
2161 case t_base_type::TYPE_BOOL
:
2162 out
<< "ReadBoolAsync(cancellationToken);";
2164 case t_base_type::TYPE_I8
:
2165 out
<< "ReadByteAsync(cancellationToken);";
2167 case t_base_type::TYPE_I16
:
2168 out
<< "ReadI16Async(cancellationToken);";
2170 case t_base_type::TYPE_I32
:
2171 out
<< "ReadI32Async(cancellationToken);";
2173 case t_base_type::TYPE_I64
:
2174 out
<< "ReadI64Async(cancellationToken);";
2176 case t_base_type::TYPE_DOUBLE
:
2177 out
<< "ReadDoubleAsync(cancellationToken);";
2180 throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase
);
2183 else if (type
->is_enum())
2185 out
<< "ReadI32Async(cancellationToken);";
2191 printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", tfield
->get_name().c_str(), type_name(type
).c_str());
2195 void t_netstd_generator::generate_deserialize_struct(ostream
& out
, t_struct
* tstruct
, string prefix
)
2197 if (is_union_enabled() && tstruct
->is_union())
2199 out
<< indent() << prefix
<< " = await " << type_name(tstruct
) << ".ReadAsync(iprot, cancellationToken);" << endl
;
2203 out
<< indent() << prefix
<< " = new " << type_name(tstruct
) << "();" << endl
2204 << indent() << "await " << prefix
<< ".ReadAsync(iprot, cancellationToken);" << endl
;
2208 void t_netstd_generator::generate_deserialize_container(ostream
& out
, t_type
* ttype
, string prefix
)
2210 out
<< indent() << "{" << endl
;
2215 if (ttype
->is_map())
2219 else if (ttype
->is_set())
2223 else if (ttype
->is_list())
2228 if (ttype
->is_map())
2230 out
<< indent() << "TMap " << obj
<< " = await iprot.ReadMapBeginAsync(cancellationToken);" << endl
;
2232 else if (ttype
->is_set())
2234 out
<< indent() << "TSet " << obj
<< " = await iprot.ReadSetBeginAsync(cancellationToken);" << endl
;
2236 else if (ttype
->is_list())
2238 out
<< indent() << "TList " << obj
<< " = await iprot.ReadListBeginAsync(cancellationToken);" << endl
;
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
;
2247 if (ttype
->is_map())
2249 generate_deserialize_map_element(out
, static_cast<t_map
*>(ttype
), prefix
);
2251 else if (ttype
->is_set())
2253 generate_deserialize_set_element(out
, static_cast<t_set
*>(ttype
), prefix
);
2255 else if (ttype
->is_list())
2257 generate_deserialize_list_element(out
, static_cast<t_list
*>(ttype
), prefix
);
2261 out
<< indent() << "}" << endl
;
2263 if (ttype
->is_map())
2265 out
<< indent() << "await iprot.ReadMapEndAsync(cancellationToken);" << endl
;
2267 else if (ttype
->is_set())
2269 out
<< indent() << "await iprot.ReadSetEndAsync(cancellationToken);" << endl
;
2271 else if (ttype
->is_list())
2273 out
<< indent() << "await iprot.ReadListEndAsync(cancellationToken);" << endl
;
2277 out
<< indent() << "}" << endl
;
2280 void t_netstd_generator::generate_deserialize_map_element(ostream
& out
, t_map
* tmap
, string prefix
)
2282 string key
= tmp("_key");
2283 string val
= tmp("_val");
2285 t_field
fkey(tmap
->get_key_type(), key
);
2286 t_field
fval(tmap
->get_val_type(), val
);
2288 out
<< indent() << declare_field(&fkey
) << endl
;
2289 out
<< indent() << declare_field(&fval
) << endl
;
2291 generate_deserialize_field(out
, &fkey
);
2292 generate_deserialize_field(out
, &fval
);
2294 out
<< indent() << prefix
<< "[" << key
<< "] = " << val
<< ";" << endl
;
2297 void t_netstd_generator::generate_deserialize_set_element(ostream
& out
, t_set
* tset
, string prefix
)
2299 string elem
= tmp("_elem");
2300 t_field
felem(tset
->get_elem_type(), elem
);
2302 out
<< indent() << declare_field(&felem
) << endl
;
2304 generate_deserialize_field(out
, &felem
);
2306 out
<< indent() << prefix
<< ".Add(" << elem
<< ");" << endl
;
2309 void t_netstd_generator::generate_deserialize_list_element(ostream
& out
, t_list
* tlist
, string prefix
)
2311 string elem
= tmp("_elem");
2312 t_field
felem(tlist
->get_elem_type(), elem
);
2314 out
<< indent() << declare_field(&felem
) << endl
;
2316 generate_deserialize_field(out
, &felem
);
2318 out
<< indent() << prefix
<< ".Add(" << elem
<< ");" << endl
;
2321 void t_netstd_generator::generate_serialize_field(ostream
& out
, t_field
* tfield
, string prefix
, bool is_propertyless
)
2323 t_type
* type
= tfield
->get_type();
2324 while (type
->is_typedef())
2326 type
= static_cast<t_typedef
*>(type
)->get_type();
2329 string name
= prefix
+ (is_propertyless
? "" : prop_name(tfield
));
2331 if (type
->is_void())
2333 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name
;
2336 if (type
->is_struct() || type
->is_xception())
2338 generate_serialize_struct(out
, static_cast<t_struct
*>(type
), name
);
2340 else if (type
->is_container())
2342 generate_serialize_container(out
, type
, name
);
2344 else if (type
->is_base_type() || type
->is_enum())
2346 out
<< indent() << "await oprot.";
2348 string nullable_name
= name
;
2350 if (type
->is_base_type())
2352 t_base_type::t_base tbase
= static_cast<t_base_type
*>(type
)->get_base();
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())
2360 out
<< "WriteBinaryAsync(";
2364 out
<< "WriteStringAsync(";
2366 out
<< name
<< ", cancellationToken);";
2368 case t_base_type::TYPE_BOOL
:
2369 out
<< "WriteBoolAsync(" << nullable_name
<< ", cancellationToken);";
2371 case t_base_type::TYPE_I8
:
2372 out
<< "WriteByteAsync(" << nullable_name
<< ", cancellationToken);";
2374 case t_base_type::TYPE_I16
:
2375 out
<< "WriteI16Async(" << nullable_name
<< ", cancellationToken);";
2377 case t_base_type::TYPE_I32
:
2378 out
<< "WriteI32Async(" << nullable_name
<< ", cancellationToken);";
2380 case t_base_type::TYPE_I64
:
2381 out
<< "WriteI64Async(" << nullable_name
<< ", cancellationToken);";
2383 case t_base_type::TYPE_DOUBLE
:
2384 out
<< "WriteDoubleAsync(" << nullable_name
<< ", cancellationToken);";
2387 throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase
);
2390 else if (type
->is_enum())
2392 out
<< "WriteI32Async((int)" << nullable_name
<< ", cancellationToken);";
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());
2402 void t_netstd_generator::generate_serialize_struct(ostream
& out
, t_struct
* tstruct
, string prefix
)
2405 out
<< indent() << "await " << prefix
<< ".WriteAsync(oprot, cancellationToken);" << endl
;
2408 void t_netstd_generator::generate_serialize_container(ostream
& out
, t_type
* ttype
, string prefix
)
2410 out
<< indent() << "{" << endl
;
2413 if (ttype
->is_map())
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
;
2419 else if (ttype
->is_set())
2421 out
<< indent() << "await oprot.WriteSetBeginAsync(new TSet(" << type_to_enum(static_cast<t_set
*>(ttype
)->get_elem_type())
2422 << ", " << prefix
<< ".Count), cancellationToken);" << endl
;
2424 else if (ttype
->is_list())
2426 out
<< indent() << "await oprot.WriteListBeginAsync(new TList("
2427 << type_to_enum(static_cast<t_list
*>(ttype
)->get_elem_type()) << ", " << prefix
<< ".Count), cancellationToken);"
2431 string iter
= tmp("_iter");
2432 if (ttype
->is_map())
2434 out
<< indent() << "foreach (" << type_name(static_cast<t_map
*>(ttype
)->get_key_type()) << " " << iter
2435 << " in " << prefix
<< ".Keys)";
2437 else if (ttype
->is_set())
2439 out
<< indent() << "foreach (" << type_name(static_cast<t_set
*>(ttype
)->get_elem_type()) << " " << iter
2440 << " in " << prefix
<< ")";
2442 else if (ttype
->is_list())
2444 out
<< indent() << "foreach (" << type_name(static_cast<t_list
*>(ttype
)->get_elem_type()) << " " << iter
2445 << " in " << prefix
<< ")";
2449 out
<< indent() << "{" << endl
;
2452 if (ttype
->is_map())
2454 generate_serialize_map_element(out
, static_cast<t_map
*>(ttype
), iter
, prefix
);
2456 else if (ttype
->is_set())
2458 generate_serialize_set_element(out
, static_cast<t_set
*>(ttype
), iter
);
2460 else if (ttype
->is_list())
2462 generate_serialize_list_element(out
, static_cast<t_list
*>(ttype
), iter
);
2466 out
<< indent() << "}" << endl
;
2468 if (ttype
->is_map())
2470 out
<< indent() << "await oprot.WriteMapEndAsync(cancellationToken);" << endl
;
2472 else if (ttype
->is_set())
2474 out
<< indent() << "await oprot.WriteSetEndAsync(cancellationToken);" << endl
;
2476 else if (ttype
->is_list())
2478 out
<< indent() << "await oprot.WriteListEndAsync(cancellationToken);" << endl
;
2482 out
<< indent() << "}" << endl
;
2485 void t_netstd_generator::generate_serialize_map_element(ostream
& out
, t_map
* tmap
, string iter
, string map
)
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
, "");
2493 void t_netstd_generator::generate_serialize_set_element(ostream
& out
, t_set
* tset
, string iter
)
2495 t_field
efield(tset
->get_elem_type(), iter
);
2496 generate_serialize_field(out
, &efield
, "");
2499 void t_netstd_generator::generate_serialize_list_element(ostream
& out
, t_list
* tlist
, string iter
)
2501 t_field
efield(tlist
->get_elem_type(), iter
);
2502 generate_serialize_field(out
, &efield
, "");
2505 void t_netstd_generator::generate_property(ostream
& out
, t_field
* tfield
, bool isPublic
, bool generateIsset
)
2507 generate_netstd_property(out
, tfield
, isPublic
, generateIsset
, "_");
2510 void t_netstd_generator::generate_netstd_property(ostream
& out
, t_field
* tfield
, bool isPublic
, bool generateIsset
, string fieldPrefix
)
2512 if ((is_serialize_enabled() || is_wcf_enabled()) && isPublic
)
2514 out
<< indent() << "[DataMember(Order = 0)]" << endl
;
2516 bool is_required
= field_is_required(tfield
);
2519 out
<< indent() << (isPublic
? "public " : "private ") << type_name(tfield
->get_type()) << " " << prop_name(tfield
) << " { get; set; }" << endl
;
2523 out
<< indent() << (isPublic
? "public " : "private ") << type_name(tfield
->get_type()) << " " << prop_name(tfield
) << endl
2524 << indent() << "{" << endl
;
2527 out
<< indent() << "get" << endl
2528 << indent() << "{" << endl
;
2531 bool use_nullable
= false;
2533 out
<< indent() << "return " << fieldPrefix
+ tfield
->get_name() << ";" << endl
;
2535 out
<< indent() << "}" << endl
2536 << indent() << "set" << endl
2537 << indent() << "{" << endl
;
2544 out
<< indent() << "__isset." << normalize_name(tfield
->get_name()) << " = value.HasValue;" << endl
;
2546 out
<< indent() << "if (value.HasValue) this." << fieldPrefix
+ tfield
->get_name() << " = value.Value;" << endl
;
2552 out
<< indent() << "__isset." << normalize_name(tfield
->get_name()) << " = true;" << endl
;
2554 out
<< indent() << "this." << fieldPrefix
+ tfield
->get_name() << " = value;" << endl
;
2558 out
<< indent() << "}" << endl
;
2560 out
<< indent() << "}" << endl
;
2565 string
t_netstd_generator::make_valid_csharp_identifier(string
const& fromName
)
2567 string str
= fromName
;
2573 // tests rely on this
2574 assert(('A' < 'Z') && ('a' < 'z') && ('0' < '9'));
2576 // if the first letter is a number, we add an additional underscore in front of it
2578 if (('0' <= c
) && (c
<= '9'))
2583 // following chars: letter, number or underscore
2584 for (size_t i
= 0; i
< str
.size(); ++i
)
2587 if (('A' > c
|| c
> 'Z') && ('a' > c
|| c
> 'z') && ('0' > c
|| c
> '9') && '_' != c
)
2589 str
.replace(i
, 1, "_");
2596 void t_netstd_generator::cleanup_member_name_mapping(void* scope
)
2598 if (member_mapping_scopes
.empty())
2600 throw "internal error: cleanup_member_name_mapping() no scope active";
2603 member_mapping_scope
& active
= member_mapping_scopes
.back();
2604 if (active
.scope_member
!= scope
)
2606 throw "internal error: cleanup_member_name_mapping() called for wrong struct";
2609 member_mapping_scopes
.pop_back();
2612 string
t_netstd_generator::get_mapped_member_name(string name
)
2614 if (!member_mapping_scopes
.empty())
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
)
2620 return iter
->second
;
2624 pverbose("no mapping for member %s\n", name
.c_str());
2628 void t_netstd_generator::prepare_member_name_mapping(t_struct
* tstruct
)
2630 prepare_member_name_mapping(tstruct
, tstruct
->get_members(), tstruct
->get_name());
2633 void t_netstd_generator::prepare_member_name_mapping(void* scope
, const vector
<t_field
*>& members
, const string
& structname
)
2636 member_mapping_scopes
.emplace_back();
2637 member_mapping_scope
& active
= member_mapping_scopes
.back();
2638 active
.scope_member
= scope
;
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
;
2646 // prevent name conflicts with struct (CS0542 error)
2647 used_member_names
.insert(structname
);
2649 // prevent name conflicts with known methods (THRIFT-2942)
2650 used_member_names
.insert("Read");
2651 used_member_names
.insert("Write");
2653 for (iter
= members
.begin(); iter
!= members
.end(); ++iter
)
2655 string oldname
= (*iter
)->get_name();
2656 string newname
= prop_name(*iter
, true);
2659 // new name conflicts with another member
2660 if (used_member_names
.find(newname
) != used_member_names
.end())
2662 pverbose("struct %s: member %s conflicts with another member\n", structname
.c_str(), newname
.c_str());
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
);
2677 string
t_netstd_generator::prop_name(t_field
* tfield
, bool suppress_mapping
)
2679 string
name(tfield
->get_name());
2680 if (suppress_mapping
)
2682 name
[0] = toupper(name
[0]);
2686 name
= get_mapped_member_name(name
);
2691 string
t_netstd_generator::type_name(t_type
* ttype
)
2693 while (ttype
->is_typedef())
2695 ttype
= static_cast<t_typedef
*>(ttype
)->get_type();
2698 if (ttype
->is_base_type())
2700 return base_type_name(static_cast<t_base_type
*>(ttype
));
2703 if (ttype
->is_map())
2705 t_map
* tmap
= static_cast<t_map
*>(ttype
);
2706 return "Dictionary<" + type_name(tmap
->get_key_type()) + ", " + type_name(tmap
->get_val_type()) + ">";
2709 if (ttype
->is_set())
2711 t_set
* tset
= static_cast<t_set
*>(ttype
);
2712 return "THashSet<" + type_name(tset
->get_elem_type()) + ">";
2715 if (ttype
->is_list())
2717 t_list
* tlist
= static_cast<t_list
*>(ttype
);
2718 return "List<" + type_name(tlist
->get_elem_type()) + ">";
2721 t_program
* program
= ttype
->get_program();
2722 if (program
!= NULL
&& program
!= program_
)
2724 string ns
= program
->get_namespace("netstd");
2727 return ns
+ "." + normalize_name(ttype
->get_name());
2731 return normalize_name(ttype
->get_name());
2734 string
t_netstd_generator::base_type_name(t_base_type
* tbase
)
2736 switch (tbase
->get_base())
2738 case t_base_type::TYPE_VOID
:
2740 case t_base_type::TYPE_STRING
:
2742 if (tbase
->is_binary())
2748 case t_base_type::TYPE_BOOL
:
2750 case t_base_type::TYPE_I8
:
2752 case t_base_type::TYPE_I16
:
2754 case t_base_type::TYPE_I32
:
2756 case t_base_type::TYPE_I64
:
2758 case t_base_type::TYPE_DOUBLE
:
2761 throw "compiler error: no C# name for base type " + t_base_type::t_base_name(tbase
->get_base());
2765 string
t_netstd_generator::declare_field(t_field
* tfield
, bool init
, string prefix
)
2767 string result
= type_name(tfield
->get_type()) + " " + prefix
+ tfield
->get_name();
2770 t_type
* ttype
= tfield
->get_type();
2771 while (ttype
->is_typedef())
2773 ttype
= static_cast<t_typedef
*>(ttype
)->get_type();
2775 if (ttype
->is_base_type() && field_has_default(tfield
))
2777 std::ofstream dummy
;
2778 result
+= " = " + render_const_value(dummy
, tfield
->get_name(), ttype
, tfield
->get_value());
2780 else if (ttype
->is_base_type())
2782 t_base_type::t_base tbase
= static_cast<t_base_type
*>(ttype
)->get_base();
2785 case t_base_type::TYPE_VOID
:
2786 throw "NO T_VOID CONSTRUCT";
2787 case t_base_type::TYPE_STRING
:
2788 result
+= " = null";
2790 case t_base_type::TYPE_BOOL
:
2791 result
+= " = false";
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
:
2799 case t_base_type::TYPE_DOUBLE
:
2800 result
+= " = (double)0";
2804 else if (ttype
->is_enum())
2806 result
+= " = (" + type_name(ttype
) + ")0";
2808 else if (ttype
->is_container())
2810 result
+= " = new " + type_name(ttype
) + "()";
2814 result
+= " = new " + type_name(ttype
) + "()";
2817 return result
+ ";";
2820 string
t_netstd_generator::function_signature(t_function
* tfunction
, string prefix
)
2822 t_type
* ttype
= tfunction
->get_returntype();
2823 return type_name(ttype
) + " " + normalize_name(prefix
+ tfunction
->get_name()) + "(" + argument_list(tfunction
->get_arglist()) + ")";
2826 string
t_netstd_generator::function_signature_async(t_function
* tfunction
, string prefix
)
2828 t_type
* ttype
= tfunction
->get_returntype();
2829 string task
= "Task";
2830 if (!ttype
->is_void())
2832 task
+= "<" + type_name(ttype
) + ">";
2835 string result
= task
+ " " + normalize_name(prefix
+ tfunction
->get_name()) + "Async(";
2836 string args
= argument_list(tfunction
->get_arglist());
2842 result
+= "CancellationToken cancellationToken = default(CancellationToken))";
2847 string
t_netstd_generator::argument_list(t_struct
* tstruct
)
2850 const vector
<t_field
*>& fields
= tstruct
->get_members();
2851 vector
<t_field
*>::const_iterator f_iter
;
2853 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
)
2863 result
+= type_name((*f_iter
)->get_type()) + " " + normalize_name((*f_iter
)->get_name());
2868 string
t_netstd_generator::type_to_enum(t_type
* type
)
2870 while (type
->is_typedef())
2872 type
= static_cast<t_typedef
*>(type
)->get_type();
2875 if (type
->is_base_type())
2877 t_base_type::t_base tbase
= static_cast<t_base_type
*>(type
)->get_base();
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
:
2890 case t_base_type::TYPE_I32
:
2892 case t_base_type::TYPE_I64
:
2894 case t_base_type::TYPE_DOUBLE
:
2895 return "TType.Double";
2898 else if (type
->is_enum())
2902 else if (type
->is_struct() || type
->is_xception())
2904 return "TType.Struct";
2906 else if (type
->is_map())
2910 else if (type
->is_set())
2914 else if (type
->is_list())
2916 return "TType.List";
2919 throw "INVALID TYPE IN type_to_enum: " + type
->get_name();
2922 void t_netstd_generator::generate_netstd_docstring_comment(ostream
& out
, string contents
)
2924 docstring_comment(out
, "/// <summary>" + endl
, "/// ", contents
, "/// </summary>" + endl
);
2927 void t_netstd_generator::generate_netstd_doc(ostream
& out
, t_field
* field
)
2929 if (field
->get_type()->is_enum())
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
);
2936 generate_netstd_doc(out
, static_cast<t_doc
*>(field
));
2940 void t_netstd_generator::generate_netstd_doc(ostream
& out
, t_doc
* tdoc
)
2942 if (tdoc
->has_doc())
2944 generate_netstd_docstring_comment(out
, tdoc
->get_doc());
2948 void t_netstd_generator::generate_netstd_doc(ostream
& out
, t_function
* tfunction
)
2950 if (tfunction
->has_doc())
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
)
2957 t_field
* p
= *p_iter
;
2958 ps
<< endl
<< "<param name=\"" << p
->get_name() << "\">";
2961 string str
= p
->get_doc();
2962 str
.erase(remove(str
.begin(), str
.end(), '\n'), str
.end());
2968 docstring_comment(out
,
2971 "<summary>" + endl
+ tfunction
->get_doc() + "</summary>" + ps
.str(),
2976 void t_netstd_generator::docstring_comment(ostream
& out
, const string
& comment_start
, const string
& line_prefix
, const string
& contents
, const string
& comment_end
)
2978 if (comment_start
!= "")
2980 out
<< indent() << comment_start
;
2983 stringstream
docs(contents
, std::ios_base::in
);
2985 while (!(docs
.eof() || docs
.fail()))
2988 docs
.getline(line
, 1024);
2990 // Just prnt a newline when the line & prefix are empty.
2991 if (strlen(line
) == 0 && line_prefix
== "" && !docs
.eof())
2995 else if (strlen(line
) > 0 || !docs
.eof())
2996 { // skip the empty last line
2997 out
<< indent() << line_prefix
<< line
<< endl
;
3000 if (comment_end
!= "")
3002 out
<< indent() << comment_end
;
3006 string
t_netstd_generator::get_enum_class_name(t_type
* type
)
3008 string package
= "";
3009 t_program
* program
= type
->get_program();
3010 if (program
!= NULL
&& program
!= program_
)
3012 package
= program
->get_namespace("netstd") + ".";
3014 return package
+ type
->get_name();
3017 THRIFT_REGISTER_GENERATOR(
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"