Merge branch '0.16.0' into master
diff --git a/ApacheThrift.nuspec b/ApacheThrift.nuspec
index 7c8e300..a5629e8 100644
--- a/ApacheThrift.nuspec
+++ b/ApacheThrift.nuspec
@@ -19,14 +19,14 @@
the "Thrift" project.
2. nuget setApiKey <your-api-key>
3. nuget pack ApacheThrift.nuspec -Symbols -SymbolPackageFormat snupkg
- 4. nuget push ApacheThrift.0.16.0.nupkg -Source https://api.nuget.org/v3/index.json
+ 4. nuget push ApacheThrift.0.17.0.nupkg -Source https://api.nuget.org/v3/index.json
-->
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata>
<id>ApacheThrift</id>
- <version>0.16.0</version>
- <title>Apache Thrift 0.16.0</title>
+ <version>0.17.0</version>
+ <title>Apache Thrift 0.17.0</title>
<authors>Apache Thrift Developers</authors>
<owners>Apache Software Foundation</owners>
<license type="expression">Apache-2.0</license>
@@ -36,7 +36,7 @@
<description>
Contains runtime libraries from lib/netstd for netstandard2.0 framework development.
</description>
- <repository type="GitHub" url="https://github.com/apache/thrift" branch="release/0.16.0" />
+ <repository type="GitHub" url="https://github.com/apache/thrift" branch="release/0.17.0" />
<tags>Apache Thrift RPC</tags>
</metadata>
<files>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8ffb528..e5f93cd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -28,7 +28,7 @@
# PACKAGE_VERSION is used by cpack scripts currently
# Both thrift_VERSION and PACKAGE_VERSION should be the same for now
-set(thrift_VERSION "0.16.0")
+set(thrift_VERSION "0.17.0")
set(PACKAGE_VERSION ${thrift_VERSION})
project("thrift" VERSION ${PACKAGE_VERSION})
diff --git a/Thrift.podspec b/Thrift.podspec
index addea6b..4e3abbd 100644
--- a/Thrift.podspec
+++ b/Thrift.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'Thrift'
- s.version = '0.16.0'
+ s.version = '0.17.0'
s.summary = "Apache Thrift is a lightweight, language-independent software stack with an associated code generation mechanism for RPC."
s.description = <<-DESC
The Apache Thrift scalable cross-language software framework for networked services development combines a software stack with a code generation engine to build services that work efficiently and seamlessly between many programming languages.
@@ -10,6 +10,6 @@
s.author = { 'Apache Thrift Developers' => 'dev@thrift.apache.org' }
s.ios.deployment_target = '9.0'
s.osx.deployment_target = '10.10'
- s.source = { :git => 'https://github.com/apache/thrift.git', :tag => 'v0.16.0' }
+ s.source = { :git => 'https://github.com/apache/thrift.git', :tag => 'v0.17.0' }
s.source_files = 'lib/swift/Sources/*.swift'
end
diff --git a/appveyor.yml b/appveyor.yml
index 8b791e4..5fe31db 100755
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -19,7 +19,7 @@
# build Apache Thrift on AppVeyor - https://ci.appveyor.com
-version: '0.16.0.{build}'
+version: '0.17.0.{build}'
shallow_clone: true
diff --git a/bower.json b/bower.json
index 46873c7..6ddfb38 100644
--- a/bower.json
+++ b/bower.json
@@ -1,6 +1,6 @@
{
"name": "thrift",
- "version": "0.16.0",
+ "version": "0.17.0",
"homepage": "https://github.com/apache/thrift.git",
"authors": [
"Apache Thrift <dev@thrift.apache.org>"
diff --git a/compiler/cpp/src/thrift/generate/t_netstd_generator.cc b/compiler/cpp/src/thrift/generate/t_netstd_generator.cc
index ff22274..d3f3a1b 100644
--- a/compiler/cpp/src/thrift/generate/t_netstd_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_netstd_generator.cc
@@ -51,6 +51,7 @@
: t_oop_generator(program)
{
(void)option_string;
+ use_net6_features = false;
suppress_deepcopy = false;
add_async_postfix = false;
use_pascal_case_properties = false;
@@ -81,6 +82,9 @@
else if (iter->first.compare("no_deepcopy") == 0) {
suppress_deepcopy = true;
}
+ else if (iter->first.compare("net6") == 0) {
+ use_net6_features = true;
+ }
else if (iter->first.compare("async_postfix") == 0) {
add_async_postfix = true;
}
@@ -159,6 +163,7 @@
pverbose("- serialize ....... %s\n", (is_serialize_enabled() ? "ON" : "off"));
pverbose("- wcf ............. %s\n", (is_wcf_enabled() ? "ON" : "off"));
pverbose("- pascal .......... %s\n", (use_pascal_case_properties ? "ON" : "off"));
+ pverbose("- net6 ............ %s\n", (use_net6_features ? "ON" : "off"));
pverbose("- no_deepcopy ..... %s\n", (suppress_deepcopy ? "ON" : "off"));
pverbose("- async_postfix ... %s\n", (add_async_postfix ? "ON" : "off"));
}
@@ -170,16 +175,16 @@
// check for reserved argument names
if( is_arg_name && (CANCELLATION_TOKEN_NAME == name))
- {
- name += "_";
- }
+ {
+ name += "_";
+ }
// un-conflict keywords by prefixing with "@"
if (netstd_keywords.find(tmp) != netstd_keywords.end())
{
return "@" + name;
}
-
+
// no changes necessary
return name;
}
@@ -302,14 +307,31 @@
}
+void t_netstd_generator::pragmas_and_directives(ostream& out)
+{
+ if( use_net6_features) {
+ out << "#nullable enable // requires C# 8.0" << endl;
+ } else {
+ out << "#nullable disable // suppress C# 8.0 nullable contexts (we still support earlier versions)" << endl;
+ }
+
+ // this one must be first
+ out << "#pragma warning disable IDE0079 // remove unnecessary pragmas" << endl;
+
+ out << "#pragma warning disable IDE0017 // object init can be simplified" << endl
+ << "#pragma warning disable IDE0028 // collection init can be simplified" << endl
+ << "#pragma warning disable IDE1006 // parts of the code use IDL spelling" << endl
+ << "#pragma warning disable CA1822 // empty " << DEEP_COPY_METHOD_NAME << "() methods still non-static" << endl;
+
+ if( ! use_net6_features) {
+ out << "#pragma warning disable IDE0083 // pattern matching \"that is not SomeType\" requires net5.0 but we still support earlier versions" << endl;
+ }
+ out << endl;
+}
+
+
void t_netstd_generator::start_netstd_namespace(ostream& out)
{
- out << "#nullable disable // suppress C# 8.0 nullable contexts (we still support earlier versions)" << endl
- << "#pragma warning disable IDE0079 // remove unnecessary pragmas" << endl
- << "#pragma warning disable IDE1006 // parts of the code use IDL spelling" << endl
- << "#pragma warning disable IDE0083 // pattern matching \"that is not SomeType\" requires net5.0 but we still support earlier versions" << endl
- << endl;
-
if (!namespace_name_.empty())
{
out << "namespace " << namespace_name_ << endl;
@@ -346,7 +368,7 @@
namespaces += "using System.Runtime.Serialization;\n";
}
- return namespaces + endl;
+ return namespaces;
}
string t_netstd_generator::netstd_thrift_usings() const
@@ -360,7 +382,7 @@
"using Thrift.Transport.Server;\n"
"using Thrift.Processor;\n";
- return namespaces + endl;
+ return namespaces;
}
void t_netstd_generator::close_generator()
@@ -393,6 +415,7 @@
reset_indent();
out << autogen_comment() << endl;
+ pragmas_and_directives(out);
start_netstd_namespace(out);
generate_netstd_doc(out, tenum);
@@ -437,8 +460,9 @@
}
reset_indent();
- out << autogen_comment() << netstd_type_usings() << endl;
+ out << autogen_comment() << netstd_type_usings() << endl << endl;
+ pragmas_and_directives(out);
start_netstd_namespace(out);
out << indent() << "public static class " << make_valid_csharp_identifier(program_name_) << "Constants" << endl;
@@ -680,7 +704,7 @@
return;
}
- if (ttype->is_map() || ttype->is_set() || ttype->is_list())
+ if (ttype->is_container())
{
if( collected_extension_types.find(key) == collected_extension_types.end())
{
@@ -702,6 +726,10 @@
t_list* tlist = static_cast<t_list*>(ttype);
collect_extensions_types(tlist->get_elem_type());
}
+ else
+ {
+ throw "compiler error: unhandled container type " + ttype->get_name();
+ }
}
return;
@@ -732,8 +760,11 @@
}
reset_indent();
- out << autogen_comment() << netstd_type_usings() << endl;
+ out << autogen_comment() << netstd_type_usings()
+ << "using Thrift.Protocol;" << endl
+ << endl << endl;
+ pragmas_and_directives(out);
start_netstd_namespace(out);
out << indent() << "public static class " << make_valid_csharp_identifier(program_name_) << "Extensions" << endl;
@@ -745,7 +776,11 @@
{
out << indent() << "public static bool Equals(this " << iter->first << " instance, object that)" << endl;
scope_up(out);
- out << indent() << "if (!(that is " << iter->first << " other)) return false;" << endl;
+ if( use_net6_features) {
+ out << indent() << "if (that is not " << iter->first << " other) return false;" << endl;
+ } else {
+ out << indent() << "if (!(that is " << iter->first << " other)) return false;" << endl;
+ }
out << indent() << "if (ReferenceEquals(instance, other)) return true;" << endl;
out << endl;
out << indent() << "return TCollections.Equals(instance, other);" << endl;
@@ -759,38 +794,42 @@
out << endl << endl;
if(! suppress_deepcopy) {
- out << indent() << "public static " << iter->first << " " << DEEP_COPY_METHOD_NAME << "(this " << iter->first << " source)" << endl;
+ out << indent() << "public static " << iter->first << nullable_field_suffix(iter->second) << " " << DEEP_COPY_METHOD_NAME << "(this " << iter->first << nullable_field_suffix(iter->second) << " source)" << endl;
scope_up(out);
out << indent() << "if (source == null)" << endl;
indent_up();
out << indent() << "return null;" << endl << endl;
indent_down();
+ string suffix("");
string tmp_instance = tmp("tmp");
out << indent() << "var " << tmp_instance << " = new " << iter->first << "(source.Count);" << endl;
if( iter->second->is_map())
{
t_map* tmap = static_cast<t_map*>(iter->second);
- string copy_key = get_deep_copy_method_call(tmap->get_key_type(), needs_typecast);
- string copy_val = get_deep_copy_method_call(tmap->get_val_type(), needs_typecast);
+ string copy_key = get_deep_copy_method_call(tmap->get_key_type(), true, needs_typecast, suffix);
+ string copy_val = get_deep_copy_method_call(tmap->get_val_type(), true, needs_typecast, suffix);
bool null_key = type_can_be_null(tmap->get_key_type());
bool null_val = type_can_be_null(tmap->get_val_type());
out << indent() << "foreach (var pair in source)" << endl;
indent_up();
- out << indent() << tmp_instance << ".Add(";
- if( null_key)
- {
- out << "(pair.Key != null) ? pair.Key" << copy_key << " : null";
+ if( use_net6_features) {
+ out << indent() << tmp_instance << ".Add(pair.Key" << copy_key;
+ out << ", pair.Value" << copy_val;
} else {
- out << "pair.Key" << copy_key;
- }
- out << ", ";
- if( null_val)
- {
- out << "(pair.Value != null) ? pair.Value" << copy_val << " : null";
- } else {
- out << "pair.Value" << copy_val;
+ out << indent() << tmp_instance << ".Add(";
+ if( null_key) {
+ out << "(pair.Key != null) ? pair.Key" << copy_key << " : null";
+ } else {
+ out << "pair.Key" << copy_key;
+ }
+ out << ", ";
+ if( null_val) {
+ out << "(pair.Value != null) ? pair.Value" << copy_val << " : null";
+ } else {
+ out << "pair.Value" << copy_val;
+ }
}
out << ");" << endl;
indent_down();
@@ -801,24 +840,28 @@
if (iter->second->is_set())
{
t_set* tset = static_cast<t_set*>(iter->second);
- copy_elm = get_deep_copy_method_call(tset->get_elem_type(), needs_typecast);
+ copy_elm = get_deep_copy_method_call(tset->get_elem_type(), true, needs_typecast, suffix);
null_elm = type_can_be_null(tset->get_elem_type());
}
else // list
{
t_list* tlist = static_cast<t_list*>(iter->second);
- copy_elm = get_deep_copy_method_call(tlist->get_elem_type(), needs_typecast);
+ copy_elm = get_deep_copy_method_call(tlist->get_elem_type(), true, needs_typecast, suffix);
null_elm = type_can_be_null(tlist->get_elem_type());
}
out << indent() << "foreach (var elem in source)" << endl;
indent_up();
- out << indent() << tmp_instance << ".Add(";
- if( null_elm)
- {
- out << "(elem != null) ? elem" << copy_elm << " : null";
+ if( use_net6_features) {
+ out << indent() << tmp_instance << ".Add(elem" << copy_elm;
} else {
- out << "elem" << copy_elm;
+ out << indent() << tmp_instance << ".Add(";
+ if( null_elm)
+ {
+ out << "(elem != null) ? elem" << copy_elm << " : null";
+ } else {
+ out << "elem" << copy_elm;
+ }
}
out << ");" << endl;
indent_down();
@@ -864,8 +907,9 @@
f_struct.open(f_struct_name.c_str());
reset_indent();
- f_struct << autogen_comment() << netstd_type_usings() << netstd_thrift_usings() << endl;
+ f_struct << autogen_comment() << netstd_type_usings() << netstd_thrift_usings() << endl << endl;
+ pragmas_and_directives(f_struct);
generate_netstd_struct_definition(f_struct, tstruct, is_exception);
f_struct.close();
@@ -915,7 +959,7 @@
// if the field is required, then we use auto-properties
if (!field_is_required((*m_iter)))
{
- out << indent() << "private " << declare_field(*m_iter, false, "_") << endl;
+ out << indent() << "private " << declare_field(*m_iter, false, true, "_") << endl;
}
}
out << endl;
@@ -930,7 +974,7 @@
if (is_required)
{
has_required_fields = true;
- }
+ }
else
{
has_non_required_fields = true;
@@ -1041,7 +1085,7 @@
{
out << ", ";
}
- out << type_name((*m_iter)->get_type()) << " " << normalize_name((*m_iter)->get_name());
+ out << type_name((*m_iter)->get_type()) << nullable_field_suffix(*m_iter) << " " << normalize_name((*m_iter)->get_name());
}
}
out << ") : this()" << endl
@@ -1113,7 +1157,7 @@
// if the field is required, then we use auto-properties
if (!field_is_required((*m_iter)))
{
- out << indent() << "private " << declare_field(*m_iter, false, "_") << endl;
+ out << indent() << "private " << declare_field(*m_iter, false, true, "_") << endl;
}
}
out << endl;
@@ -1146,8 +1190,9 @@
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
bool needs_typecast = false;
+ string suffix("");
t_type* ttype = (*m_iter)->get_type();
- string copy_op = get_deep_copy_method_call(ttype, needs_typecast);
+ string copy_op = get_deep_copy_method_call(ttype, true, needs_typecast, suffix);
bool is_required = field_is_required(*m_iter);
generate_null_check_begin( out, *m_iter);
@@ -1511,8 +1556,9 @@
f_union.open(f_union_name.c_str());
reset_indent();
- f_union << autogen_comment() << netstd_type_usings() << netstd_thrift_usings() << endl;
+ f_union << autogen_comment() << netstd_type_usings() << netstd_thrift_usings() << endl << endl;
+ pragmas_and_directives(f_union);
generate_netstd_union_definition(f_union, tunion);
f_union.close();
@@ -1531,7 +1577,7 @@
out << indent() << "public abstract global::System.Threading.Tasks.Task WriteAsync(TProtocol tProtocol, CancellationToken " << CANCELLATION_TOKEN_NAME << ");" << endl
<< indent() << "public readonly int Isset;" << endl
- << indent() << "public abstract object Data { get; }" << endl
+ << indent() << "public abstract object" << nullable_suffix() <<" Data { get; }" << endl
<< indent() << "protected " << tunion->get_name() << "(int isset)" << endl
<< indent() << "{" << endl;
indent_up();
@@ -1542,79 +1588,136 @@
const vector<t_field*>& fields = tunion->get_members();
vector<t_field*>::const_iterator f_iter;
- out << indent() << "public override bool Equals(object that)" << endl;
+ out << indent() << "public override bool Equals(object" << nullable_suffix() << " that)" << endl;
scope_up(out);
- out << indent() << "if (!(that is " << tunion->get_name() << " other)) return false;" << endl;
+ if( use_net6_features) {
+ out << indent() << "if (that is not " << tunion->get_name() << " other) return false;" << endl;
+ } else {
+ out << indent() << "if (!(that is " << tunion->get_name() << " other)) return false;" << endl;
+ }
out << indent() << "if (ReferenceEquals(this, other)) return true;" << endl;
out << endl;
out << indent() << "if(this.Isset != other.Isset) return false;" << endl;
out << endl;
- out << indent() << "switch (Isset)" << endl;
- scope_up(out);
- for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
- {
- bool needs_typecast = false;
- string copy_op = get_deep_copy_method_call((*f_iter)->get_type(), needs_typecast);
- out << indent() << "case " << (*f_iter)->get_key() << ":" << endl;
- indent_up();
- out << indent() << "return Equals(As_" << (*f_iter)->get_name() << ", other.As_" << (*f_iter)->get_name() << ");" << endl;
+ if(use_net6_features) {
+ out << indent() << "return Isset switch" << endl;
+ scope_up(out);
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
+ {
+ bool needs_typecast = false;
+ string suffix("");
+ get_deep_copy_method_call((*f_iter)->get_type(), false, needs_typecast, suffix);
+ out << indent() << (*f_iter)->get_key() << " => Equals(As_" << (*f_iter)->get_name() << ", other.As_" << (*f_iter)->get_name() << ")," << endl;
+ }
+ out << indent() << "_ => true," << endl;
indent_down();
+ out << indent() << "};" << endl;
+ } else {
+ out << indent() << "switch (Isset)" << endl;
+ scope_up(out);
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
+ {
+ bool needs_typecast = false;
+ string suffix("");
+ get_deep_copy_method_call((*f_iter)->get_type(), false, needs_typecast, suffix);
+ out << indent() << "case " << (*f_iter)->get_key() << ":" << endl;
+ indent_up();
+ out << indent() << "return Equals(As_" << (*f_iter)->get_name() << ", other.As_" << (*f_iter)->get_name() << ");" << endl;
+ indent_down();
+ }
+ out << indent() << "default:" << endl;
+ indent_up();
+ out << indent() << "return true;" << endl;
+ indent_down();
+ scope_down(out);
}
- out << indent() << "default:" << endl;
- indent_up();
- out << indent() << "return true;" << endl;
- indent_down();
- indent_down();
- scope_down(out);
scope_down(out);
out << endl;
out << indent() << "public override int GetHashCode()" << endl;
out << indent() << "{" << endl;
indent_up();
- out << indent() << "switch (Isset)" << endl;
- out << indent() << "{" << endl;
- indent_up();
- for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
- {
- bool needs_typecast = false;
- string copy_op = get_deep_copy_method_call((*f_iter)->get_type(), needs_typecast);
- out << indent() << "case " << (*f_iter)->get_key() << ":" << endl;
- indent_up();
- out << indent() << "return As_" << (*f_iter)->get_name() << ".GetHashCode();" << endl;
- indent_down();
- }
- out << indent() << "default:" << endl;
- indent_up();
- out << indent() << "return (new ___undefined()).GetHashCode();" << endl;
- indent_down();
- indent_down();
- out << indent() << "}" << endl;
- indent_down();
- out << indent() << "}" << endl << endl;
-
- if( ! suppress_deepcopy) {
- out << indent() << "public " << tunion->get_name() << " DeepCopy()" << endl;
+ if(use_net6_features) {
+ out << indent() << "return Isset switch" << endl;
out << indent() << "{" << endl;
indent_up();
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
+ {
+ string null_coalesce(is_nullable_type((*f_iter)->get_type()) ? "?" : "");
+ out << indent() << (*f_iter)->get_key() << " => As_" << (*f_iter)->get_name() << null_coalesce << ".GetHashCode()";
+ if( null_coalesce.size() > 0) {
+ out << " ?? 0";
+ }
+ out << "," << endl;
+ }
+ out << indent() << "_ => (new ___undefined()).GetHashCode()" << endl;
+ indent_down();
+ out << indent() << "};" << endl;
+ } else {
out << indent() << "switch (Isset)" << endl;
out << indent() << "{" << endl;
indent_up();
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
{
- bool needs_typecast = false;
- string copy_op = get_deep_copy_method_call((*f_iter)->get_type(), needs_typecast);
+ string null_coalesce(is_nullable_type((*f_iter)->get_type()) ? "?" : "");
out << indent() << "case " << (*f_iter)->get_key() << ":" << endl;
indent_up();
- out << indent() << "return new " << (*f_iter)->get_name() << "(As_" << (*f_iter)->get_name() << copy_op << ");" << endl;
+ out << indent() << "return As_" << (*f_iter)->get_name() << null_coalesce << ".GetHashCode()";
+ if( null_coalesce.size() > 0) {
+ out << " ?? 0";
+ }
+ out << ";" << endl;
indent_down();
}
out << indent() << "default:" << endl;
indent_up();
- out << indent() << "return new ___undefined();" << endl;
+ out << indent() << "return (new ___undefined()).GetHashCode();" << endl;
indent_down();
indent_down();
out << indent() << "}" << endl;
+ }
+ indent_down();
+ out << indent() << "}" << endl << endl;
+
+ if( ! suppress_deepcopy) {
+ out << indent() << "public " << tunion->get_name() << " " << DEEP_COPY_METHOD_NAME << "()" << endl;
+ out << indent() << "{" << endl;
+ indent_up();
+ if(use_net6_features) {
+ out << indent() << "return Isset switch" << endl;
+ out << indent() << "{" << endl;
+ indent_up();
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
+ {
+ bool needs_typecast = false;
+ string suffix("");
+ string copy_op = get_deep_copy_method_call((*f_iter)->get_type(), false, needs_typecast, suffix);
+ out << indent() << (*f_iter)->get_key() << " => new " << (*f_iter)->get_name() << "(As_" << (*f_iter)->get_name() << suffix << copy_op << ")," << endl;
+ }
+ out << indent() << "_ => new ___undefined()" << endl;
+ indent_down();
+ out << indent() << "};" << endl;
+ } else {
+ out << indent() << "switch (Isset)" << endl;
+ out << indent() << "{" << endl;
+ indent_up();
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter)
+ {
+ bool needs_typecast = false;
+ string suffix("");
+ string copy_op = get_deep_copy_method_call((*f_iter)->get_type(), false, needs_typecast, suffix);
+ out << indent() << "case " << (*f_iter)->get_key() << ":" << endl;
+ indent_up();
+ out << indent() << "return new " << (*f_iter)->get_name() << "(As_" << (*f_iter)->get_name() << suffix << copy_op << ");" << endl;
+ indent_down();
+ }
+ out << indent() << "default:" << endl;
+ indent_up();
+ out << indent() << "return new ___undefined();" << endl;
+ indent_down();
+ indent_down();
+ out << indent() << "}" << endl;
+ }
indent_down();
out << indent() << "}" << endl << endl;
}
@@ -1623,11 +1726,11 @@
out << indent() << "{" << endl;
indent_up();
- out << indent() << "public override object Data { get { return null; } }" << endl
+ out << indent() << "public override object" << nullable_suffix() <<" Data { get { return null; } }" << endl
<< indent() << "public ___undefined() : base(0) {}" << endl << endl;
if( ! suppress_deepcopy) {
- out << indent() << "public new ___undefined DeepCopy()" << endl;
+ out << indent() << "public new ___undefined " << DEEP_COPY_METHOD_NAME << "()" << endl;
out << indent() << "{" << endl;
indent_up();
out << indent() << "return new ___undefined();" << endl;
@@ -1663,13 +1766,17 @@
void t_netstd_generator::generate_netstd_union_class(ostream& out, t_struct* tunion, t_field* tfield)
{
- out << indent() << "public " << type_name(tfield->get_type()) << " As_" << tfield->get_name() << endl;
+ out << indent() << "public " << type_name(tfield->get_type()) << nullable_field_suffix(tfield) << " As_" << tfield->get_name() << endl;
out << indent() << "{" << endl;
indent_up();
out << indent() << "get" << endl;
out << indent() << "{" << endl;
indent_up();
- out << indent() << "return (" << tfield->get_key() << " == Isset) ? (" << type_name(tfield->get_type()) << ")Data : default(" << type_name(tfield->get_type()) << ");" << endl;
+ out << indent() << "return (" << tfield->get_key() << " == Isset) && (Data != null)"
+ << " ? (" << type_name(tfield->get_type()) << nullable_field_suffix(tfield) << ")Data"
+ << " : default"
+ << (use_net6_features ? "" : ("(" + type_name(tfield->get_type()) + ")"))
+ << ";" << endl;
indent_down();
out << indent() << "}" << endl;
indent_down();
@@ -1681,8 +1788,8 @@
out << indent() << "{" << endl;
indent_up();
- out << indent() << "private " << type_name(tfield->get_type()) << " _data;" << endl
- << indent() << "public override object Data { get { return _data; } }" << endl
+ out << indent() << "private readonly " << type_name(tfield->get_type()) << " _data;" << endl
+ << indent() << "public override object" << nullable_suffix() <<" Data { get { return _data; } }" << endl
<< indent() << "public " << tfield->get_name() << "(" << type_name(tfield->get_type()) << " data) : base("<< tfield->get_key() <<")" << endl
<< indent() << "{" << endl;
indent_up();
@@ -1691,20 +1798,25 @@
out << indent() << "}" << endl;
if( ! suppress_deepcopy) {
- out << indent() << "public new " << tfield->get_name() << " DeepCopy()" << endl;
+ out << indent() << "public new " << tfield->get_name() << " " << DEEP_COPY_METHOD_NAME << "()" << endl;
out << indent() << "{" << endl;
indent_up();
bool needs_typecast = false;
- string copy_op = get_deep_copy_method_call(tfield->get_type(), needs_typecast);
+ string suffix("");
+ string copy_op = get_deep_copy_method_call(tfield->get_type(), true, needs_typecast, suffix);
out << indent() << "return new " << tfield->get_name() << "(_data" << copy_op << ");" << endl;
indent_down();
out << indent() << "}" << endl << endl;
}
- out << indent() << "public override bool Equals(object that)" << endl;
+ out << indent() << "public override bool Equals(object" << nullable_suffix() << " that)" << endl;
out << indent() << "{" << endl;
indent_up();
- out << indent() << "if (!(that is " << tunion->get_name() << " other)) return false;" << endl;
+ if(use_net6_features) {
+ out << indent() << "if (that is not " << tunion->get_name() << " other) return false;" << endl;
+ } else {
+ out << indent() << "if (!(that is " << tunion->get_name() << " other)) return false;" << endl;
+ }
out << indent() << "if (ReferenceEquals(this, other)) return true;" << endl;
out << endl;
out << indent() << "return Equals( _data, other.As_" << tfield->get_name() << ");" << endl;
@@ -1735,7 +1847,7 @@
<< indent() << "field.ID = " << tfield->get_key() << ";" << endl
<< indent() << "await oprot.WriteFieldBeginAsync(field, " << CANCELLATION_TOKEN_NAME << ");" << endl;
- generate_serialize_field(out, tfield, "_data", true);
+ generate_serialize_field(out, tfield, "_data", true, false);
out << indent() << "await oprot.WriteFieldEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl
<< indent() << "await oprot.WriteFieldStopAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl
@@ -1756,11 +1868,15 @@
void t_netstd_generator::generate_netstd_struct_equals(ostream& out, t_struct* tstruct)
{
- out << indent() << "public override bool Equals(object that)" << endl
+ out << indent() << "public override bool Equals(object" << nullable_suffix() << " that)" << endl
<< indent() << "{" << endl;
indent_up();
- out << indent() << "if (!(that is " << type_name(tstruct,false) << " other)) return false;" << endl
- << indent() << "if (ReferenceEquals(this, other)) return true;" << endl;
+ if(use_net6_features) {
+ out << indent() << "if (that is not " << type_name(tstruct,false) << " other) return false;" << endl;
+ } else {
+ out << indent() << "if (!(that is " << type_name(tstruct,false) << " other)) return false;" << endl;
+ }
+ out << indent() << "if (ReferenceEquals(this, other)) return true;" << endl;
const vector<t_field*>& fields = tstruct->get_members();
@@ -1838,7 +1954,7 @@
out << "TCollections.GetHashCode(" << prop_name((*f_iter)) << ")";
}
else {
- out << prop_name((*f_iter)) << ".GetHashCode()";
+ out << prop_name(*f_iter) << ".GetHashCode()";
}
out << ";" << endl;
@@ -1862,8 +1978,9 @@
f_service.open(f_service_name.c_str());
reset_indent();
- f_service << autogen_comment() << netstd_type_usings() << netstd_thrift_usings() << endl;
+ f_service << autogen_comment() << netstd_type_usings() << netstd_thrift_usings() << endl << endl;
+ pragmas_and_directives(f_service);
start_netstd_namespace(f_service);
f_service << indent() << "public partial class " << normalize_name(service_name_) << endl
@@ -2106,7 +2223,8 @@
out << indent() << "if (" << tmpvar << ".__isset.success)" << endl
<< indent() << "{" << endl;
indent_up();
- out << indent() << "return " << tmpvar << ".Success;" << endl;
+ string nullable_value = nullable_value_access((*functions_iterator)->get_returntype());
+ out << indent() << "return " << tmpvar << ".Success" << nullable_value << ";" << endl;
indent_down();
out << indent() << "}" << endl;
}
@@ -2118,7 +2236,7 @@
out << indent() << "if (" << tmpvar << ".__isset." << get_isset_name(normalize_name((*x_iter)->get_name())) << ")" << endl
<< indent() << "{" << endl;
indent_up();
- out << indent() << "throw " << tmpvar << "." << prop_name(*x_iter) << ";" << endl;
+ out << indent() << "throw " << tmpvar << "." << prop_name(*x_iter) << nullable_value_access((*x_iter)->get_type()) << ";" << endl;
indent_down();
out << indent() << "}" << endl;
}
@@ -2162,9 +2280,9 @@
indent_up();
out << indent() << "private readonly IAsync _iAsync;" << endl
- << indent() << "private readonly ILogger<AsyncProcessor> _logger;" << endl
+ << indent() << "private readonly ILogger<AsyncProcessor>" << nullable_suffix() << " _logger;" << endl
<< endl
- << indent() << "public AsyncProcessor(IAsync iAsync, ILogger<AsyncProcessor> logger = default)";
+ << indent() << "public AsyncProcessor(IAsync iAsync, ILogger<AsyncProcessor>" << nullable_suffix() << " logger = default)";
if (!extends.empty())
{
@@ -2194,7 +2312,9 @@
if (extends.empty())
{
- out << indent() << "protected Dictionary<string, ProcessFunction> processMap_ = new Dictionary<string, ProcessFunction>();" << endl;
+ out << indent() << "protected Dictionary<string, ProcessFunction> processMap_ = new"
+ << (use_net6_features ? "" : " Dictionary<string, ProcessFunction>") // Simplify new expression (IDE0090)
+ << "();" << endl;
}
out << endl;
@@ -2229,7 +2349,7 @@
indent_up();
out << indent() << "var msg = await iprot.ReadMessageBeginAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl
<< endl
- << indent() << "processMap_.TryGetValue(msg.Name, out ProcessFunction fn);" << endl
+ << indent() << "processMap_.TryGetValue(msg.Name, out var fn);" << endl
<< endl
<< indent() << "if (fn == null)" << endl
<< indent() << "{" << endl;
@@ -2654,15 +2774,15 @@
if (ttype->is_map())
{
- out << indent() << "TMap " << obj << " = await iprot.ReadMapBeginAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl;
+ out << indent() << "var " << obj << " = await iprot.ReadMapBeginAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl;
}
else if (ttype->is_set())
{
- out << indent() << "TSet " << obj << " = await iprot.ReadSetBeginAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl;
+ out << indent() << "var " << obj << " = await iprot.ReadSetBeginAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl;
}
else if (ttype->is_list())
{
- out << indent() << "TList " << obj << " = await iprot.ReadListBeginAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl;
+ out << indent() << "var " << obj << " = await iprot.ReadListBeginAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl;
}
out << indent() << prefix << " = new " << type_name(ttype) << "(" << obj << ".Count);" << endl;
@@ -2712,8 +2832,8 @@
t_field fkey(tmap->get_key_type(), key);
t_field fval(tmap->get_val_type(), val);
- out << indent() << declare_field(&fkey) << endl;
- out << indent() << declare_field(&fval) << endl;
+ out << indent() << declare_field(&fkey, false, false) << endl;
+ out << indent() << declare_field(&fval, false, false) << endl;
generate_deserialize_field(out, &fkey);
generate_deserialize_field(out, &fval);
@@ -2726,7 +2846,7 @@
string elem = tmp("_elem");
t_field felem(tset->get_elem_type(), elem);
- out << indent() << declare_field(&felem) << endl;
+ out << indent() << declare_field(&felem, false, false) << endl;
generate_deserialize_field(out, &felem);
@@ -2738,19 +2858,20 @@
string elem = tmp("_elem");
t_field felem(tlist->get_elem_type(), elem);
- out << indent() << declare_field(&felem) << endl;
+ out << indent() << declare_field(&felem, false, false) << endl;
generate_deserialize_field(out, &felem);
out << indent() << prefix << ".Add(" << elem << ");" << endl;
}
-void t_netstd_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix, bool is_propertyless)
+void t_netstd_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix, bool is_propertyless, bool allow_nullable)
{
t_type* type = tfield->get_type();
type = resolve_typedef( type);
string name = prefix + (is_propertyless ? "" : prop_name(tfield));
+ string nullable_name = name + (allow_nullable ? nullable_value_access(type) : "");
if (type->is_void())
{
@@ -2769,8 +2890,6 @@
{
out << indent() << "await oprot.";
- string nullable_name = name;
-
if (type->is_base_type())
{
t_base_type::t_base tbase = static_cast<t_base_type*>(type)->get_base();
@@ -2813,7 +2932,7 @@
}
else if (type->is_enum())
{
- out << "WriteI32Async((int)" << nullable_name << ", " << CANCELLATION_TOKEN_NAME << ");";
+ out << "WriteI32Async((int)" << name << ", " << CANCELLATION_TOKEN_NAME << ");";
}
out << endl;
}
@@ -2831,9 +2950,6 @@
void t_netstd_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix)
{
- out << indent() << "{" << endl;
- indent_up();
-
if (ttype->is_map())
{
out << indent() << "await oprot.WriteMapBeginAsync(new TMap(" << type_to_enum(static_cast<t_map*>(ttype)->get_key_type())
@@ -2901,29 +3017,26 @@
{
out << indent() << "await oprot.WriteListEndAsync(" << CANCELLATION_TOKEN_NAME << ");" << endl;
}
-
- indent_down();
- out << indent() << "}" << endl;
}
void t_netstd_generator::generate_serialize_map_element(ostream& out, t_map* tmap, string iter, string map)
{
t_field kfield(tmap->get_key_type(), iter);
- generate_serialize_field(out, &kfield, "");
+ generate_serialize_field(out, &kfield, "", false, false);
t_field vfield(tmap->get_val_type(), map + "[" + iter + "]");
- generate_serialize_field(out, &vfield, "");
+ generate_serialize_field(out, &vfield, "", false, false);
}
void t_netstd_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter)
{
t_field efield(tset->get_elem_type(), iter);
- generate_serialize_field(out, &efield, "");
+ generate_serialize_field(out, &efield, "", false, false);
}
void t_netstd_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter)
{
t_field efield(tlist->get_elem_type(), iter);
- generate_serialize_field(out, &efield, "");
+ generate_serialize_field(out, &efield, "", false, false);
}
void t_netstd_generator::generate_property(ostream& out, t_field* tfield, bool isPublic, bool generateIsset)
@@ -2937,12 +3050,23 @@
{
out << indent() << "[DataMember(Order = 0)]" << endl;
}
- out << indent() << (isPublic ? "public " : "private ") << type_name(tfield->get_type()) << " " << prop_name(tfield);
+
+ out << indent()
+ << (isPublic ? "public " : "private ")
+ << type_name(tfield->get_type())
+ << nullable_field_suffix(tfield)
+ << " "
+ << prop_name(tfield)
+ ;
bool is_required = field_is_required(tfield);
if (is_required)
{
- out << " { get; set; }" << endl;
+ out << " { get; set; }";
+ if( use_net6_features && (!force_member_nullable(tfield))) {
+ out << initialize_field(tfield) << ";";
+ }
+ out << endl;
}
else
{
@@ -3214,6 +3338,105 @@
return get_mapped_member_name(fname);
}
+bool t_netstd_generator::is_nullable_type(t_type* ttype) {
+ ttype = resolve_typedef(ttype);
+
+ if (ttype->is_enum()) {
+ return false;
+ }
+
+ if (ttype->is_base_type()) {
+ t_base_type::t_base tbase = static_cast<t_base_type*>(ttype)->get_base();
+ switch (tbase)
+ {
+ case t_base_type::TYPE_STRING:
+ return true; // both binary and string
+ default:
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+string t_netstd_generator::nullable_suffix() {
+ if(use_net6_features) {
+ return "?";
+ } else {
+ return "";
+ }
+}
+
+
+string t_netstd_generator::nullable_field_suffix(t_field* tfield) {
+ if(field_is_required(tfield) && (!force_member_nullable(tfield)))
+ return "";
+ else
+ return nullable_field_suffix(tfield->get_type());
+}
+
+
+string t_netstd_generator::nullable_field_suffix(t_type* ttype) {
+ if( ! use_net6_features) {
+ return "";
+ }
+
+ ttype = resolve_typedef(ttype);
+
+ if (ttype->is_enum()) {
+ return "";
+ }
+
+ if (ttype->is_base_type()) {
+ t_base_type::t_base tbase = static_cast<t_base_type*>(ttype)->get_base();
+ switch (tbase)
+ {
+ case t_base_type::TYPE_STRING:
+ return nullable_suffix();
+ default:
+ return "";
+ }
+ }
+
+ return nullable_suffix();
+}
+
+string t_netstd_generator::nullable_value_access(t_type* ttype) {
+ if( ! use_net6_features)
+ return "";
+
+ ttype = resolve_typedef(ttype);
+
+ // this code uses the null-forgiving operator and therefore assumes that the variable
+ // has been properly checked against an isset guard or null
+ if (ttype->is_base_type()) {
+ t_base_type::t_base tbase = static_cast<t_base_type*>(ttype)->get_base();
+ switch (tbase)
+ {
+ case t_base_type::TYPE_STRING:
+ return "!";
+ default:
+ return "";
+ }
+ }
+
+ if (ttype->is_container() || ttype->is_struct() || ttype->is_xception()) {
+ return "!";
+ }
+
+ return "";
+}
+
+bool t_netstd_generator::force_member_nullable(t_field* tfield) {
+ // IMPORTANT:
+ // If tfield is a struct that contains a required field of the same type (directly or indirectly),
+ // auto-initializing such a member field would immediately produce an OOM, or at least unexpectedly
+ // allocate potentially large amounts of memory -> ALWAYS leave containers and struct members nullable
+ t_type* ttype = resolve_typedef(tfield->get_type());
+ return ttype->is_struct() || ttype->is_container();
+}
+
string t_netstd_generator::type_name(t_type* ttype, bool with_namespace)
{
ttype = resolve_typedef(ttype);
@@ -3232,7 +3455,7 @@
if (ttype->is_set())
{
t_set* tset = static_cast<t_set*>(ttype);
- return "THashSet<" + type_name(tset->get_elem_type()) + ">";
+ return "HashSet<" + type_name(tset->get_elem_type()) + ">";
}
if (ttype->is_list())
@@ -3266,8 +3489,7 @@
case t_base_type::TYPE_VOID:
return "void";
case t_base_type::TYPE_STRING:
- if (tbase->is_binary())
- {
+ if (tbase->is_binary()) {
return "byte[]";
} else {
return "string";
@@ -3289,10 +3511,14 @@
}
}
-string t_netstd_generator::get_deep_copy_method_call(t_type* ttype, bool& needs_typecast)
+string t_netstd_generator::get_deep_copy_method_call(t_type* ttype, bool is_not_null, bool& needs_typecast, string& suffix)
{
ttype = resolve_typedef(ttype);
+ // if is_not_null is set, then the surrounding code already explicitly tests against != null
+ string null_check("");
+
+ suffix = "";
needs_typecast = false;
if (ttype->is_base_type())
{
@@ -3300,11 +3526,17 @@
switch (tbase)
{
case t_base_type::TYPE_STRING:
- if (ttype->is_binary())
- {
- return ".ToArray()";
+ if (ttype->is_binary()) {
+ suffix = nullable_suffix();
+ if( use_net6_features) {
+ null_check = is_not_null ? "!" : " ?? Array.Empty<byte>()";
+ }
+ return ".ToArray()" + null_check;
} else {
- return ""; // simple assignment will do, strings are immutable in C#
+ if( use_net6_features) {
+ null_check = is_not_null ? "!" : " ?? string.Empty";
+ }
+ return null_check; // simple assignment will do, strings are immutable in C#
}
break;
default:
@@ -3315,63 +3547,116 @@
{
return ""; // simple assignment will do
}
+ else if (is_union_enabled() && ttype->is_struct() && static_cast<t_struct*>(ttype)->is_union())
+ {
+ needs_typecast = (! ttype->is_container());
+ suffix = nullable_suffix();
+ if( use_net6_features) {
+ null_check = is_not_null ? "!" : " ?? new "+ttype->get_name() +".___undefined()";
+ }
+ return "." + DEEP_COPY_METHOD_NAME + "()" + null_check;
+ }
else
{
- needs_typecast = (! ttype->is_container());
- return "." + DEEP_COPY_METHOD_NAME + "()";
+ needs_typecast = (! ttype->is_container());
+ suffix = nullable_suffix();
+ if( use_net6_features) {
+ null_check = is_not_null ? "!" : " ?? new()";
+ }
+ return "." + DEEP_COPY_METHOD_NAME + "()" + null_check;
}
+
+ throw "UNEXPECTED TYPE IN get_deep_copy_method_call: " + ttype->get_name();
}
-string t_netstd_generator::declare_field(t_field* tfield, bool init, string prefix)
+string t_netstd_generator::declare_field(t_field* tfield, bool init, bool allow_nullable, string prefix)
{
- string result = type_name(tfield->get_type()) + " " + prefix + tfield->get_name();
+ string result = type_name(tfield->get_type())
+ + (allow_nullable ? nullable_field_suffix(tfield) : "")
+ + " "
+ + prefix + tfield->get_name()
+ ;
if (init)
{
- t_type* ttype = tfield->get_type();
- ttype = resolve_typedef(ttype);
- if (ttype->is_base_type() && field_has_default(tfield))
+ result += initialize_field(tfield);
+ }
+
+ return result + ";";
+}
+
+string t_netstd_generator::initialize_field(t_field* tfield)
+{
+ t_type* ttype = tfield->get_type();
+ ttype = resolve_typedef(ttype);
+
+ if (ttype->is_base_type() && field_has_default(tfield))
+ {
+ std::ofstream dummy;
+ return " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value());
+ }
+ else if (force_member_nullable(tfield))
+ {
+ return ""; // see force_member_nullable() why this is necessary
+ }
+ else if (ttype->is_base_type())
+ {
+ t_base_type::t_base tbase = static_cast<t_base_type*>(ttype)->get_base();
+ switch (tbase)
{
- std::ofstream dummy;
- result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value());
- }
- else if (ttype->is_base_type())
- {
- t_base_type::t_base tbase = static_cast<t_base_type*>(ttype)->get_base();
- switch (tbase)
- {
- case t_base_type::TYPE_VOID:
- throw "NO T_VOID CONSTRUCT";
- case t_base_type::TYPE_STRING:
- result += " = null";
- break;
- case t_base_type::TYPE_BOOL:
- result += " = false";
- break;
- case t_base_type::TYPE_I8:
- case t_base_type::TYPE_I16:
- case t_base_type::TYPE_I32:
- case t_base_type::TYPE_I64:
- result += " = 0";
- break;
- case t_base_type::TYPE_DOUBLE:
- result += " = (double)0";
- break;
+ case t_base_type::TYPE_VOID:
+ throw "NO T_VOID CONSTRUCT";
+ case t_base_type::TYPE_STRING:
+ if(use_net6_features && field_is_required(tfield)) {
+ if (ttype->is_binary()) {
+ return " = Array.Empty<byte>()";
+ } else {
+ return " = string.Empty";
+ }
+ } else {
+ return " = null";
}
- }
- else if (ttype->is_enum())
- {
- result += " = (" + type_name(ttype) + ")0";
- }
- else if (ttype->is_container())
- {
- result += " = new " + type_name(ttype) + "()";
- }
- else
- {
- result += " = new " + type_name(ttype) + "()";
+ break;
+ case t_base_type::TYPE_BOOL:
+ return " = false";
+ break;
+ case t_base_type::TYPE_I8:
+ case t_base_type::TYPE_I16:
+ case t_base_type::TYPE_I32:
+ case t_base_type::TYPE_I64:
+ return " = 0";
+ break;
+ case t_base_type::TYPE_DOUBLE:
+ return " = 0.0";
+ break;
}
}
- return result + ";";
+ else if (ttype->is_enum())
+ {
+ return " = default";
+ }
+ else if (ttype->is_container())
+ {
+ if(use_net6_features) {
+ return " = new()";
+ } else {
+ return " = new " + type_name(ttype) + "()";
+ }
+ }
+ else if (ttype->is_struct())
+ {
+ t_struct* tstruct = static_cast<t_struct*>(ttype);
+ if(use_net6_features) {
+ if(tstruct->is_union()) {
+ return " = new " + type_name(ttype) + ".___undefined()";
+ } else {
+ return " = new()";
+ }
+ } else {
+ return " = new " + type_name(ttype) + "()";
+ }
+ }
+
+ throw "UNEXPECTED TYPE IN initialize_field: " + ttype->get_name();
}
string t_netstd_generator::function_signature(t_function* tfunction, string prefix)
@@ -3421,7 +3706,7 @@
}
if( with_types) {
- result += type_name((*f_iter)->get_type()) + " ";
+ result += type_name((*f_iter)->get_type()) + nullable_field_suffix(*f_iter) + " ";
}
result += normalize_name((*f_iter)->get_name(),true);
@@ -3582,6 +3867,7 @@
" serial: Add serialization support to generated classes.\n"
" union: Use new union typing, which includes a static read function for union types.\n"
" pascal: Generate Pascal Case property names according to Microsoft naming convention.\n"
- " no_deepcopy: Suppress generation of DeepCopy() method.\n"
+ " net6: Enable features that require net6 and C# 8 or higher.\n"
+ " no_deepcopy: Suppress generation of " + DEEP_COPY_METHOD_NAME + "() method.\n"
" async_postfix: Append \"Async\" to all service methods (maintains compatibility with existing code).\n"
)
diff --git a/compiler/cpp/src/thrift/generate/t_netstd_generator.h b/compiler/cpp/src/thrift/generate/t_netstd_generator.h
index 31226f2..982cd26 100644
--- a/compiler/cpp/src/thrift/generate/t_netstd_generator.h
+++ b/compiler/cpp/src/thrift/generate/t_netstd_generator.h
@@ -69,16 +69,16 @@
map<string, int> get_keywords_list() const;
// overrides
- void init_generator();
- void close_generator();
- void generate_consts(vector<t_const*> consts);
+ void init_generator() override;
+ void close_generator() override;
+ void generate_consts(vector<t_const*> consts) override;
void generate_consts(ostream& out, vector<t_const*> consts);
- void generate_typedef(t_typedef* ttypedef);
- void generate_enum(t_enum* tenum);
+ void generate_typedef(t_typedef* ttypedef) override;
+ void generate_enum(t_enum* tenum) override;
void generate_enum(ostream& out, t_enum* tenum);
- void generate_struct(t_struct* tstruct);
- void generate_xception(t_struct* txception);
- void generate_service(t_service* tservice);
+ void generate_struct(t_struct* tstruct) override;
+ void generate_xception(t_struct* txception) override;
+ void generate_service(t_service* tservice) override;
// additional files
void generate_extensions_file();
@@ -116,7 +116,7 @@
void generate_deserialize_set_element(ostream& out, t_set* tset, string prefix = "");
void generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix = "");
void generate_deserialize_list_element(ostream& out, t_list* list, string prefix = "");
- void generate_serialize_field(ostream& out, t_field* tfield, string prefix = "", bool is_propertyless = false);
+ void generate_serialize_field(ostream& out, t_field* tfield, string prefix = "", bool is_propertyless = false, bool allow_nullable = true);
void generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix = "");
void generate_serialize_container(ostream& out, t_type* ttype, string prefix = "");
void generate_serialize_map_element(ostream& out, t_map* tmap, string iter, string map);
@@ -139,7 +139,7 @@
string type_name(t_type* ttype, bool with_namespace = true);
string base_type_name(t_base_type* tbase);
- string declare_field(t_field* tfield, bool init = false, string prefix = "");
+ string declare_field(t_field* tfield, bool init = false, bool allow_nullable = true, string prefix = "");
string function_signature_async(t_function* tfunction, string prefix = "", int mode = MODE_FULL_DECL);
string function_signature(t_function* tfunction, string prefix = "");
string argument_list(t_struct* tstruct, bool with_types = true);
@@ -148,19 +148,23 @@
string func_name(t_function* tfunc, bool suppress_mapping = false);
string func_name(std::string fname, bool suppress_mapping = false);
string convert_to_pascal_case(const string& str);
- string get_enum_class_name(t_type* type);
+ string get_enum_class_name(t_type* type) override;
protected:
std::string autogen_comment() override {
- return std::string("/**\n")
- + " * <auto-generated>\n"
- + " * " + autogen_summary() + "\n"
- + " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n"
- + " * </auto-generated>\n"
- " */\n"
- ;
+ string comment = "/**\n";
+ if( ! use_net6_features) {
+ comment += " * <auto-generated>\n";
+ }
+ comment += " * " + autogen_summary() + "\n";
+ comment += " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n";
+ if( ! use_net6_features) {
+ comment += " * </auto-generated>\n";
+ }
+ comment += " */\n";
+ return comment;
}
-
+
private:
string namespace_name_;
@@ -172,6 +176,7 @@
bool wcf_;
bool use_pascal_case_properties;
bool suppress_deepcopy;
+ bool use_net6_features;
bool add_async_postfix;
string wcf_namespace_;
@@ -191,11 +196,20 @@
void cleanup_member_name_mapping(void* scope);
string get_mapped_member_name(string oldname);
string get_isset_name(const string& str);
- string get_deep_copy_method_call(t_type* ttype, bool& needs_typecast);
+ string get_deep_copy_method_call(t_type* ttype, bool is_not_null, bool& needs_typecast, string& suffix);
void collect_extensions_types(t_struct* tstruct);
void collect_extensions_types(t_type* ttype);
void generate_extensions(ostream& out, map<string, t_type*> types);
void reset_indent();
void generate_null_check_begin(ostream& out, t_field* tfield);
void generate_null_check_end(ostream& out, t_field* tfield);
+ string initialize_field(t_field* tfield);
+
+ void pragmas_and_directives(ostream& out);
+ bool is_nullable_type(t_type* ttype);
+ bool force_member_nullable(t_field* tfield); // see there
+ string nullable_suffix(); // unconditionally
+ string nullable_field_suffix(t_field* tfield); // depends on field type
+ string nullable_field_suffix(t_type* ttype); // depends on field type
+ string nullable_value_access(t_type* ttype); // depends on field type
};
diff --git a/compiler/cpp/src/thrift/parse/t_field.h b/compiler/cpp/src/thrift/parse/t_field.h
index 4be8770..f0a607d 100644
--- a/compiler/cpp/src/thrift/parse/t_field.h
+++ b/compiler/cpp/src/thrift/parse/t_field.h
@@ -41,6 +41,7 @@
: type_(type),
name_(name),
key_(0),
+ req_(T_OPT_IN_REQ_OUT),
value_(nullptr),
xsd_optional_(false),
xsd_nillable_(false),
diff --git a/compiler/cpp/src/thrift/version.h b/compiler/cpp/src/thrift/version.h
index bce719a..2a4b925 100644
--- a/compiler/cpp/src/thrift/version.h
+++ b/compiler/cpp/src/thrift/version.h
@@ -24,6 +24,6 @@
#pragma once
#endif // _MSC_VER
-#define THRIFT_VERSION "0.16.0"
+#define THRIFT_VERSION "0.17.0"
#endif // _THRIFT_VERSION_H_
diff --git a/configure.ac b/configure.ac
index 32c2471..1ab550a 100755
--- a/configure.ac
+++ b/configure.ac
@@ -20,7 +20,7 @@
AC_PREREQ(2.65)
AC_CONFIG_MACRO_DIR([./aclocal])
-AC_INIT([thrift], [0.16.0])
+AC_INIT([thrift], [0.17.0])
AC_CONFIG_AUX_DIR([.])
diff --git a/contrib/Rebus/Properties/AssemblyInfo.cs b/contrib/Rebus/Properties/AssemblyInfo.cs
index 97c89d1..cc3204a 100644
--- a/contrib/Rebus/Properties/AssemblyInfo.cs
+++ b/contrib/Rebus/Properties/AssemblyInfo.cs
@@ -34,5 +34,5 @@
[assembly: Guid("0af10984-40d3-453d-b1e5-421529e8c7e2")]
-[assembly: AssemblyVersion("0.16.0.0")]
-[assembly: AssemblyFileVersion("0.16.0.0")]
+[assembly: AssemblyVersion("0.17.0.0")]
+[assembly: AssemblyFileVersion("0.17.0.0")]
diff --git a/contrib/thrift-maven-plugin/pom.xml b/contrib/thrift-maven-plugin/pom.xml
index 1290895..da8491d 100644
--- a/contrib/thrift-maven-plugin/pom.xml
+++ b/contrib/thrift-maven-plugin/pom.xml
@@ -32,7 +32,7 @@
<artifactId>thrift-maven-plugin</artifactId>
<packaging>maven-plugin</packaging>
<name>thrift-maven-plugin</name>
- <version>0.16.0</version>
+ <version>0.17.0</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
diff --git a/contrib/thrift.spec b/contrib/thrift.spec
index feb95a1..92af91e 100644
--- a/contrib/thrift.spec
+++ b/contrib/thrift.spec
@@ -28,7 +28,7 @@
License: Apache License v2.0
Group: Development
Summary: RPC and serialization framework
-Version: 0.16.0
+Version: 0.17.0
Release: 0
URL: http://thrift.apache.org
Packager: Thrift Developers <dev@thrift.apache.org>
diff --git a/contrib/zeromq/csharp/AssemblyInfo.cs b/contrib/zeromq/csharp/AssemblyInfo.cs
index dc59f23..8f46c92 100644
--- a/contrib/zeromq/csharp/AssemblyInfo.cs
+++ b/contrib/zeromq/csharp/AssemblyInfo.cs
@@ -36,7 +36,7 @@
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
-[assembly: AssemblyVersion("0.16.0.0")]
+[assembly: AssemblyVersion("0.17.0.0")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
diff --git a/debian/changelog b/debian/changelog
index 52f87e3..c570028 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+thrift (0.16.0) stable; urgency=low
+
+ * update to 0.16.0
+
+ -- Apache Thrift Developers <dev@thrift.apache.org> Wed, 20 Jan 2022 21:00:00 +0100
+
thrift (0.15.0) stable; urgency=low
* update to 0.15.0
diff --git a/doap.rdf b/doap.rdf
index eabb232..36c54e6 100755
--- a/doap.rdf
+++ b/doap.rdf
@@ -57,6 +57,11 @@
<release rdf:parseType="Collection">
<Version>
<name>Apache Thrift</name>
+ <created>2022-01-20</created>
+ <revision>0.16.0</revision>
+ </Version>
+ <Version>
+ <name>Apache Thrift</name>
<created>2021-08-03</created>
<revision>0.15.0</revision>
</Version>
diff --git a/doc/specs/idl.md b/doc/specs/idl.md
index 019c7f6..1c6a94a 100644
--- a/doc/specs/idl.md
+++ b/doc/specs/idl.md
@@ -1,6 +1,6 @@
## Thrift interface description language
-For Thrift version 0.16.0.
+For Thrift version 0.17.0.
The Thrift interface definition language (IDL) allows for the definition of [Thrift Types](/docs/types). A Thrift IDL file is processed by the Thrift code generator to produce code for the various target languages to support the defined structs and services in the IDL file.
diff --git a/lib/cpp/src/thrift/protocol/TProtocol.h b/lib/cpp/src/thrift/protocol/TProtocol.h
index 867ceb0..b691c41 100644
--- a/lib/cpp/src/thrift/protocol/TProtocol.h
+++ b/lib/cpp/src/thrift/protocol/TProtocol.h
@@ -22,7 +22,7 @@
#ifdef _WIN32
// Need to come before any Windows.h includes
-#include <Winsock2.h>
+#include <winsock2.h>
#endif
#include <thrift/transport/TTransport.h>
diff --git a/lib/cpp/src/thrift/windows/GetTimeOfDay.cpp b/lib/cpp/src/thrift/windows/GetTimeOfDay.cpp
index ac24124..d369605 100644
--- a/lib/cpp/src/thrift/windows/GetTimeOfDay.cpp
+++ b/lib/cpp/src/thrift/windows/GetTimeOfDay.cpp
@@ -38,7 +38,7 @@
}
#else
#define WIN32_LEAN_AND_MEAN
-#include <Winsock2.h>
+#include <winsock2.h>
#include <cstdint>
#include <sstream>
#include <thrift/transport/TTransportException.h>
diff --git a/lib/cpp/src/thrift/windows/SocketPair.h b/lib/cpp/src/thrift/windows/SocketPair.h
index 86bf431..74b65df 100644
--- a/lib/cpp/src/thrift/windows/SocketPair.h
+++ b/lib/cpp/src/thrift/windows/SocketPair.h
@@ -29,7 +29,7 @@
#endif
// Win32
-#include <Winsock2.h>
+#include <winsock2.h>
#include <thrift/thrift-config.h>
int thrift_socketpair(int d, int type, int protocol, THRIFT_SOCKET sv[2]);
diff --git a/lib/cpp/src/thrift/windows/Sync.h b/lib/cpp/src/thrift/windows/Sync.h
index f5b8a05..a5b2ac5 100644
--- a/lib/cpp/src/thrift/windows/Sync.h
+++ b/lib/cpp/src/thrift/windows/Sync.h
@@ -29,11 +29,23 @@
// Including Windows.h can conflict with Winsock2 usage, and also
// adds problematic macros like min() and max(). Try to work around:
+#ifndef NOMINMAX
#define NOMINMAX
+#define _THRIFT_UNDEF_NOMINMAX
+#endif
+#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
+#define _THRIFT_UNDEF_WIN32_LEAN_AND_MEAN
+#endif
#include <Windows.h>
+#ifdef _THRIFT_UNDEF_NOMINMAX
#undef NOMINMAX
+#undef _THRIFT_UNDEF_NOMINMAX
+#endif
+#ifdef _THRIFT_UNDEF_WIN32_LEAN_AND_MEAN
#undef WIN32_LEAN_AND_MEAN
+#undef _THRIFT_UNDEF_WIN32_LEAN_AND_MEAN
+#endif
/*
Lightweight synchronization objects that only make sense on Windows. For cross-platform
diff --git a/lib/cpp/src/thrift/windows/WinFcntl.h b/lib/cpp/src/thrift/windows/WinFcntl.h
index 4816fc5..39e5efd 100644
--- a/lib/cpp/src/thrift/windows/WinFcntl.h
+++ b/lib/cpp/src/thrift/windows/WinFcntl.h
@@ -33,7 +33,7 @@
#endif
// Win32
-#include <Winsock2.h>
+#include <winsock2.h>
#include <thrift/transport/PlatformSocket.h>
extern "C" {
diff --git a/lib/cpp/src/thrift/windows/config.h b/lib/cpp/src/thrift/windows/config.h
index ce10c55..19296d6 100644
--- a/lib/cpp/src/thrift/windows/config.h
+++ b/lib/cpp/src/thrift/windows/config.h
@@ -57,7 +57,7 @@
#include <thrift/windows/SocketPair.h>
// windows
-#include <Winsock2.h>
+#include <winsock2.h>
#include <ws2tcpip.h>
#ifndef __MINGW32__
diff --git a/lib/cpp/test/OpenSSLManualInitTest.cpp b/lib/cpp/test/OpenSSLManualInitTest.cpp
index 935a205..bf6c153 100644
--- a/lib/cpp/test/OpenSSLManualInitTest.cpp
+++ b/lib/cpp/test/OpenSSLManualInitTest.cpp
@@ -21,7 +21,7 @@
// which will cause the test to fail
#define MANUAL_OPENSSL_INIT 1
#ifdef _WIN32
-#include <WinSock2.h>
+#include <winsock2.h>
#endif
#include <boost/test/unit_test.hpp>
diff --git a/lib/d/src/thrift/base.d b/lib/d/src/thrift/base.d
index 471a253..56a4f60 100644
--- a/lib/d/src/thrift/base.d
+++ b/lib/d/src/thrift/base.d
@@ -50,7 +50,7 @@
/// The Thrift version string, used for informative purposes.
// Note: This is currently hardcoded, but will likely be filled in by the build
// system in future versions.
-enum VERSION = "0.16.0";
+enum VERSION = "0.17.0";
/**
* Functions used for logging inside Thrift.
diff --git a/lib/dart/pubspec.yaml b/lib/dart/pubspec.yaml
index 8dbb367..a2f4b90 100644
--- a/lib/dart/pubspec.yaml
+++ b/lib/dart/pubspec.yaml
@@ -16,7 +16,7 @@
# under the License.
name: thrift
-version: 0.16.0
+version: 0.17.0
description: >
A Dart library for Apache Thrift
author: Apache Thrift Developers <dev@thrift.apache.org>
diff --git a/lib/delphi/src/Thrift.pas b/lib/delphi/src/Thrift.pas
index bf9ac05..f8841f3 100644
--- a/lib/delphi/src/Thrift.pas
+++ b/lib/delphi/src/Thrift.pas
@@ -28,7 +28,7 @@
Thrift.Protocol;
const
- Version = '0.16.0';
+ Version = '0.17.0';
type
TException = Thrift.Exception.TException; // compatibility alias
diff --git a/lib/erl/src/thrift.app.src b/lib/erl/src/thrift.app.src
index 0ce69b9..9c30c8a 100644
--- a/lib/erl/src/thrift.app.src
+++ b/lib/erl/src/thrift.app.src
@@ -22,7 +22,7 @@
{description, "Thrift bindings"},
% The version of the applicaton
- {vsn, "0.16.0"},
+ {vsn, "0.17.0"},
% All modules used by the application.
{modules, [
diff --git a/lib/haxe/haxelib.json b/lib/haxe/haxelib.json
index 2d73ad8..5448e5f 100644
--- a/lib/haxe/haxelib.json
+++ b/lib/haxe/haxelib.json
@@ -10,7 +10,7 @@
"framework"
],
"description": "Haxe bindings for the Apache Thrift RPC and serialization framework",
- "version": "0.16.0",
+ "version": "0.17.0",
"releasenote": "Licensed under Apache License, Version 2.0. The Apache Thrift compiler needs to be installed separately.",
"contributors": ["ApacheThrift"],
"dependencies": {
diff --git a/lib/java/gradle.properties b/lib/java/gradle.properties
index fbb194d..8d4f0e4 100644
--- a/lib/java/gradle.properties
+++ b/lib/java/gradle.properties
@@ -1,7 +1,7 @@
# This file is shared currently between this Gradle build and the
# Ant builds for fd303 and JavaScript. Keep the dotted notation for
# the properties to minimize the changes in the dependencies.
-thrift.version=0.16.0
+thrift.version=0.17.0
thrift.groupid=org.apache.thrift
release=false
diff --git a/lib/js/package-lock.json b/lib/js/package-lock.json
index b6633ac..8e764e3 100644
--- a/lib/js/package-lock.json
+++ b/lib/js/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "thrift",
- "version": "0.16.0",
+ "version": "0.17.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/lib/js/package.json b/lib/js/package.json
index dfed941..ff57bf7 100644
--- a/lib/js/package.json
+++ b/lib/js/package.json
@@ -1,6 +1,6 @@
{
"name": "thrift",
- "version": "0.16.0",
+ "version": "0.17.0",
"description": "Thrift is a software framework for scalable cross-language services development.",
"main": "./src/thrift",
"author": {
diff --git a/lib/js/src/thrift.js b/lib/js/src/thrift.js
index 9933d60..17eb302 100644
--- a/lib/js/src/thrift.js
+++ b/lib/js/src/thrift.js
@@ -46,7 +46,7 @@
* @const {string} Version
* @memberof Thrift
*/
- Version: '0.16.0',
+ Version: '0.17.0',
/**
* Thrift IDL type string to Id mapping.
diff --git a/lib/lua/Thrift.lua b/lib/lua/Thrift.lua
index 32c442b..252cded 100644
--- a/lib/lua/Thrift.lua
+++ b/lib/lua/Thrift.lua
@@ -48,7 +48,7 @@
return count
end
-version = '0.16.0'
+version = '0.17.0'
TType = {
STOP = 0,
diff --git a/lib/netstd/Tests/Thrift.IntegrationTests/Thrift.IntegrationTests.csproj b/lib/netstd/Tests/Thrift.IntegrationTests/Thrift.IntegrationTests.csproj
index 56123dd..8c1b6a9 100644
--- a/lib/netstd/Tests/Thrift.IntegrationTests/Thrift.IntegrationTests.csproj
+++ b/lib/netstd/Tests/Thrift.IntegrationTests/Thrift.IntegrationTests.csproj
@@ -22,7 +22,7 @@
<TargetFramework>net6.0</TargetFramework>
<AssemblyName>Thrift.IntegrationTests</AssemblyName>
<PackageId>Thrift.IntegrationTests</PackageId>
- <Version>0.16.0.0</Version>
+ <Version>0.17.0.0</Version>
<OutputType>Exe</OutputType>
<GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
<GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
diff --git a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Impl/Thrift5253/MyService.cs b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Impl/Thrift5253/MyService.cs
index 660b2b7..f423376 100644
--- a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Impl/Thrift5253/MyService.cs
+++ b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Impl/Thrift5253/MyService.cs
@@ -26,30 +26,30 @@
{
class MyServiceImpl : MyService.IAsync
{
- public Task<AsyncProcessor> AsyncProcessor_(AsyncProcessor input, CancellationToken cancellationToken = default)
+ public Task<AsyncProcessor> AsyncProcessor_(AsyncProcessor? input, CancellationToken cancellationToken = default)
{
- return Task.FromResult(new AsyncProcessor() { Foo = input.Foo });
+ return Task.FromResult(new AsyncProcessor() { Foo = input?.Foo ?? 0 });
}
- public Task<BrokenResult> Broken(BrokenArgs input, CancellationToken cancellationToken = default)
+ public Task<BrokenResult> Broken(BrokenArgs? input, CancellationToken cancellationToken = default)
{
- return Task.FromResult(new BrokenResult() { Foo = input.Foo });
+ return Task.FromResult(new BrokenResult() { Foo = input?.Foo ?? 0 });
}
- public Task<Client> Client_(Client input, CancellationToken cancellationToken = default)
+ public Task<Client> Client_(Client? input, CancellationToken cancellationToken = default)
{
_ = cancellationToken;
- return Task.FromResult(new Client() { Foo = input.Foo });
+ return Task.FromResult(new Client() { Foo = input?.Foo ?? 0 });
}
- public Task<IAsync> IAsync_(IAsync input, CancellationToken cancellationToken = default)
+ public Task<IAsync> IAsync_(IAsync? input, CancellationToken cancellationToken = default)
{
- return Task.FromResult(new IAsync() { Foo = input.Foo });
+ return Task.FromResult(new IAsync() { Foo = input?.Foo ?? 0 });
}
- public Task<InternalStructs> InternalStructs_(InternalStructs input, CancellationToken cancellationToken = default)
+ public Task<InternalStructs> InternalStructs_(InternalStructs? input, CancellationToken cancellationToken = default)
{
- return Task.FromResult(new InternalStructs() { Foo = input.Foo });
+ return Task.FromResult(new InternalStructs() { Foo = input?.Foo ?? 0 });
}
public Task TestAsync(CancellationToken cancellationToken = default)
@@ -62,9 +62,9 @@
return Task.CompletedTask;
}
- public Task<WorksRslt> Works(WorksArrrgs input, CancellationToken cancellationToken = default)
+ public Task<WorksRslt> Works(WorksArrrgs? input, CancellationToken cancellationToken = default)
{
- return Task.FromResult(new WorksRslt() { Foo = input.Foo });
+ return Task.FromResult(new WorksRslt() { Foo = input?.Foo ?? 0 });
}
}
}
diff --git a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift.PublicInterfaces.Compile.Tests.csproj b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift.PublicInterfaces.Compile.Tests.csproj
index 0d2770d..42a139c 100644
--- a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift.PublicInterfaces.Compile.Tests.csproj
+++ b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift.PublicInterfaces.Compile.Tests.csproj
@@ -19,7 +19,7 @@
-->
<PropertyGroup>
- <ThriftVersion>0.16.0</ThriftVersion>
+ <ThriftVersion>0.17.0</ThriftVersion>
<ThriftVersionOutput>Thrift version $(ThriftVersion)</ThriftVersionOutput>
<TargetFramework>net6.0</TargetFramework>
<Version>$(ThriftVersion).0</Version>
@@ -68,14 +68,14 @@
<Error Condition="$('$(ThriftBinaryVersion)'::StartsWith('$(ThriftVersionOutput)')) == true" Text="Thrift version returned: '$(ThriftBinaryVersion)' is not equal to the projects version '$(ThriftVersionOutput)'." />
<Message Importance="high" Text="Generating tests with thrift binary: '$(PathToThrift)'" />
<!-- Generate the thrift test files -->
- <Exec Command="$(PathToThrift) -gen netstd:wcf,union,serial -r ./CassandraTest.thrift" />
- <Exec Command="$(PathToThrift) -gen netstd:wcf,union,serial -r ./optional_required_default.thrift" />
- <Exec Command="$(PathToThrift) -gen netstd:wcf,union,serial -r ./name_conflicts.thrift" />
- <Exec Command="$(PathToThrift) -gen netstd:wcf,union,serial -r ./../../../../test/ThriftTest.thrift" />
- <Exec Command="$(PathToThrift) -gen netstd:wcf,union,serial -r ./../../../../contrib/fb303/if/fb303.thrift" />
- <Exec Command="$(PathToThrift) -gen netstd:wcf,union,serial -r ./Thrift5253.thrift" />
- <Exec Command="$(PathToThrift) -gen netstd:wcf,union,serial -r ./Thrift5320.thrift" />
- <Exec Command="$(PathToThrift) -gen netstd:wcf,union,serial -r ./Thrift5382.thrift" />
+ <Exec Command="$(PathToThrift) -gen netstd:wcf,union,serial,net6 -r ./CassandraTest.thrift" />
+ <Exec Command="$(PathToThrift) -gen netstd:wcf,union,serial,net6 -r ./optional_required_default.thrift" />
+ <Exec Command="$(PathToThrift) -gen netstd:wcf,union,serial,net6 -r ./name_conflicts.thrift" />
+ <Exec Command="$(PathToThrift) -gen netstd:wcf,union,serial,net6 -r ./../../../../test/ThriftTest.thrift" />
+ <Exec Command="$(PathToThrift) -gen netstd:wcf,union,serial,net6 -r ./../../../../contrib/fb303/if/fb303.thrift" />
+ <Exec Command="$(PathToThrift) -gen netstd:wcf,union,serial,net6 -r ./Thrift5253.thrift" />
+ <Exec Command="$(PathToThrift) -gen netstd:wcf,union,serial,net6 -r ./Thrift5320.thrift" />
+ <Exec Command="$(PathToThrift) -gen netstd:wcf,union,serial,net6 -r ./Thrift5382.thrift" />
</Target>
</Project>
diff --git a/lib/netstd/Tests/Thrift.Tests/Collections/TCollectionsTests.cs b/lib/netstd/Tests/Thrift.Tests/Collections/TCollectionsTests.cs
index 778d24c..49108d1 100644
--- a/lib/netstd/Tests/Thrift.Tests/Collections/TCollectionsTests.cs
+++ b/lib/netstd/Tests/Thrift.Tests/Collections/TCollectionsTests.cs
@@ -83,8 +83,8 @@
[TestMethod]
public void TCollection_Set_Equals_Primitive_Test()
{
- var collection1 = new THashSet<int> {1,2,3};
- var collection2 = new THashSet<int> {1,2,3};
+ var collection1 = new HashSet<int> {1,2,3};
+ var collection2 = new HashSet<int> {1,2,3};
Assert.IsTrue(TCollections.Equals(collection1, collection2));
Assert.IsTrue(collection1.SequenceEqual(collection2));
}
@@ -92,8 +92,8 @@
[TestMethod]
public void TCollection_Set_Equals_Primitive_Different_Test()
{
- var collection1 = new THashSet<int> { 1, 2, 3 };
- var collection2 = new THashSet<int> { 1, 2 };
+ var collection1 = new HashSet<int> { 1, 2, 3 };
+ var collection2 = new HashSet<int> { 1, 2 };
Assert.IsFalse(TCollections.Equals(collection1, collection2));
Assert.IsFalse(collection1.SequenceEqual(collection2));
@@ -105,8 +105,8 @@
[TestMethod]
public void TCollection_Set_Equals_Objects_Test()
{
- var collection1 = new THashSet<ExampleClass> { new ExampleClass { X = 1 }, new ExampleClass { X = 2 } };
- var collection2 = new THashSet<ExampleClass> { new ExampleClass { X = 1 }, new ExampleClass { X = 2 } };
+ var collection1 = new HashSet<ExampleClass> { new ExampleClass { X = 1 }, new ExampleClass { X = 2 } };
+ var collection2 = new HashSet<ExampleClass> { new ExampleClass { X = 1 }, new ExampleClass { X = 2 } };
Assert.IsTrue(TCollections.Equals(collection1, collection2));
Assert.IsTrue(collection1.SequenceEqual(collection2));
}
@@ -114,8 +114,8 @@
[TestMethod]
public void TCollection_Set_Set_Equals_Objects_Test()
{
- var collection1 = new THashSet<THashSet<ExampleClass>> { new THashSet<ExampleClass> { new ExampleClass { X = 1 }, new ExampleClass { X = 2 } } };
- var collection2 = new THashSet<THashSet<ExampleClass>> { new THashSet<ExampleClass> { new ExampleClass { X = 1 }, new ExampleClass { X = 2 } } };
+ var collection1 = new HashSet<HashSet<ExampleClass>> { new HashSet<ExampleClass> { new ExampleClass { X = 1 }, new ExampleClass { X = 2 } } };
+ var collection2 = new HashSet<HashSet<ExampleClass>> { new HashSet<ExampleClass> { new ExampleClass { X = 1 }, new ExampleClass { X = 2 } } };
Assert.IsTrue(TCollections.Equals(collection1, collection2));
Assert.IsFalse(collection1.SequenceEqual(collection2)); // SequenceEqual() calls Equals() of the inner list instead of SequenceEqual()
}
@@ -123,7 +123,7 @@
[TestMethod]
public void TCollection_Set_Equals_OneAndTheSameObject_Test()
{
- var collection1 = new THashSet<ExampleClass> { new ExampleClass { X = 1 }, new ExampleClass { X = 2 } };
+ var collection1 = new HashSet<ExampleClass> { new ExampleClass { X = 1 }, new ExampleClass { X = 2 } };
var collection2 = collection1; // references to one and the same collection
Assert.IsTrue(TCollections.Equals(collection1, collection2));
Assert.IsTrue(collection1.SequenceEqual(collection2));
diff --git a/lib/netstd/Tests/Thrift.Tests/Collections/THashSetTests.cs b/lib/netstd/Tests/Thrift.Tests/Collections/THashSetTests.cs
index 8de573e..73921ea 100644
--- a/lib/netstd/Tests/Thrift.Tests/Collections/THashSetTests.cs
+++ b/lib/netstd/Tests/Thrift.Tests/Collections/THashSetTests.cs
@@ -1,4 +1,4 @@
-// Licensed to the Apache Software Foundation(ASF) under one
+// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
@@ -22,6 +22,8 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Thrift.Collections;
+#pragma warning disable IDE0063 // simplify using
+
namespace Thrift.Tests.Collections
{
// ReSharper disable once InconsistentNaming
@@ -33,7 +35,7 @@
{
const int value = 1;
- var hashSet = new THashSet<int> {value};
+ var hashSet = new HashSet<int> {value};
Assert.IsTrue(hashSet.Contains(value));
diff --git a/lib/netstd/Tests/Thrift.Tests/DataModel/DeepCopy.cs b/lib/netstd/Tests/Thrift.Tests/DataModel/DeepCopy.cs
index 84fcab8..afffed5 100644
--- a/lib/netstd/Tests/Thrift.Tests/DataModel/DeepCopy.cs
+++ b/lib/netstd/Tests/Thrift.Tests/DataModel/DeepCopy.cs
@@ -24,8 +24,6 @@
using OptReqDefTest;
using Thrift.Collections;
-#nullable disable // this is just test code, we leave it at that
-
namespace Thrift.Tests.DataModel
{
// ReSharper disable once InconsistentNaming
@@ -51,7 +49,7 @@
VerifyIdenticalContent(first, InitializeInstance(new RaceDetails()));
}
- private RaceDetails MakeNestedRaceDetails(int nesting)
+ private RaceDetails? MakeNestedRaceDetails(int nesting)
{
if (++nesting > 1)
return null;
@@ -61,7 +59,7 @@
return instance;
}
- private jack MakeNestedUnion(int nesting)
+ private jack? MakeNestedUnion(int nesting)
{
if (++nesting > 1)
return null;
@@ -88,11 +86,11 @@
instance.Req_one = default;
instance.Req_two = default;
instance.Req_three = default;
- instance.Req_four = default;
- instance.Req_five = default;
+ Assert.IsNotNull(instance.Req_four);
+ Assert.IsNotNull(instance.Req_five);
instance.Req_six = default;
instance.Req_seven = default;;
- instance.Req_eight = default;
+ instance.Req_eight = default;
// leave non-required fields unset again
Assert.IsFalse(instance.__isset.def_one);
@@ -119,15 +117,15 @@
Assert.AreEqual(instance.Req_two_with_value, 2.22);
Assert.AreEqual(instance.Req_three_with_value, 3);
Assert.AreEqual(instance.Req_four_with_value, "four");
- Assert.AreEqual("five", Encoding.UTF8.GetString(instance.Req_five_with_value));
+ Assert.AreEqual("five", Encoding.UTF8.GetString(instance.Req_five_with_value!));
- Assert.IsTrue(instance.Req_six_with_value.Count == 1);
+ Assert.IsTrue(instance.Req_six_with_value!.Count == 1);
Assert.AreEqual(instance.Req_six_with_value[0], 6 );
- Assert.IsTrue(instance.Req_seven_with_value.Count == 1);
+ Assert.IsTrue(instance.Req_seven_with_value!.Count == 1);
Assert.IsTrue(instance.Req_seven_with_value.Contains(7));
- Assert.IsTrue(instance.Req_eight_with_value.Count == 1);
+ Assert.IsTrue(instance.Req_eight_with_value!.Count == 1);
Assert.IsTrue(instance.Req_eight_with_value[8] == 8);
Assert.IsTrue(instance.__isset.def_one_with_value);
@@ -144,12 +142,16 @@
if (nesting < 2)
{
instance.Far_list = new List<Distance>() { Distance.foo, Distance.bar, Distance.baz };
- instance.Far_set = new THashSet<Distance>() { Distance.foo, Distance.bar, Distance.baz };
+ instance.Far_set = new HashSet<Distance>() { Distance.foo, Distance.bar, Distance.baz };
instance.Far_map = new Dictionary<Distance, Distance>() { [Distance.foo] = Distance.foo, [Distance.bar] = Distance.bar, [Distance.baz] = Distance.baz };
- instance.Far_set_list = new THashSet<List<Distance>>() { new List<Distance>() { Distance.foo } };
- instance.Far_list_map_set = new List<Dictionary<sbyte, THashSet<Distance>>>() { new Dictionary<sbyte, THashSet<Distance>>() { [1] = new THashSet<Distance>() { Distance.baz } } };
- instance.Far_map_dist_to_rds = new Dictionary<Distance, List<RaceDetails>>() { [Distance.bar] = new List<RaceDetails>() { MakeNestedRaceDetails(nesting) } };
+ instance.Far_set_list = new HashSet<List<Distance>>() { new List<Distance>() { Distance.foo } };
+ instance.Far_list_map_set = new List<Dictionary<sbyte, HashSet<Distance>>>() { new Dictionary<sbyte, HashSet<Distance>>() { [1] = new HashSet<Distance>() { Distance.baz } } };
+
+ instance.Far_map_dist_to_rds = new Dictionary<Distance, List<RaceDetails>>() { [Distance.bar] = new List<RaceDetails>() };
+ var details = MakeNestedRaceDetails(nesting);
+ if (details != null)
+ instance.Far_map_dist_to_rds[Distance.bar].Add(details);
instance.Req_nested = MakeNestedRaceDetails(nesting);
Assert.IsFalse(instance.__isset.opt_nested);
@@ -245,19 +247,19 @@
instance.Triplesix = ModifyValue(instance.Triplesix);
}
- private jack ModifyValue(jack value, int level)
+ private jack? ModifyValue(jack? value, int level)
{
if (++level > 4)
return value;
if (value == null)
value = MakeNestedUnion(0);
- Debug.Assert(value.As_nested_struct != null);
+ Debug.Assert(value?.As_nested_struct != null);
ModifyInstance(value.As_nested_struct, level);
return value;
}
- private RaceDetails ModifyValue(RaceDetails value, int level)
+ private RaceDetails? ModifyValue(RaceDetails? value, int level)
{
if (++level > 4)
return value;
@@ -268,7 +270,7 @@
return value;
}
- private Dictionary<Distance, List<RaceDetails>> ModifyValue(Dictionary<Distance, List<RaceDetails>> value, int level)
+ private Dictionary<Distance, List<RaceDetails>> ModifyValue(Dictionary<Distance, List<RaceDetails>>? value, int level)
{
if (value == null)
value = new Dictionary<Distance, List<RaceDetails>>();
@@ -283,29 +285,30 @@
if (value.TryGetValue(Distance.bar, out var list) && (list.Count > 0))
{
ModifyInstance(list[0], level);
- list.Add(null);
+ //list.Add(null); -- Thrift does not allow null values in containers
}
- value[Distance.baz] = null;
+ // Thrift does not allow null values in containers
+ //value[Distance.baz] = null;
return value;
}
- private static List<Dictionary<sbyte, THashSet<Distance>>> ModifyValue(List<Dictionary<sbyte, THashSet<Distance>>> value)
+ private static List<Dictionary<sbyte, HashSet<Distance>>> ModifyValue(List<Dictionary<sbyte, HashSet<Distance>>>? value)
{
if (value == null)
- value = new List<Dictionary<sbyte, THashSet<Distance>>>();
+ value = new List<Dictionary<sbyte, HashSet<Distance>>>();
if (value.Count == 0)
- value.Add(new Dictionary<sbyte, THashSet<Distance>>());
- else
- value.Add(null);
+ value.Add(new Dictionary<sbyte, HashSet<Distance>>());
+ //else
+ //value.Add(null); --Thrift does not allow null values in containers
sbyte key = (sbyte)(value[0].Count + 10);
if (value[0].Count == 0)
- value[0].Add(key, new THashSet<Distance>());
- else
- value[0].Add(key, null);
+ value[0].Add(key, new HashSet<Distance>());
+ //else
+ //value[0].Add(key, null); --Thrift does not allow null values in containers
foreach (var entry in value)
{
@@ -327,15 +330,15 @@
return value;
}
- private static THashSet<List<Distance>> ModifyValue(THashSet<List<Distance>> value)
+ private static HashSet<List<Distance>> ModifyValue(HashSet<List<Distance>>? value)
{
if (value == null)
- value = new THashSet<List<Distance>>();
+ value = new HashSet<List<Distance>>();
if (value.Count == 0)
value.Add(new List<Distance>());
- else
- value.Add(null);
+ //else
+ //value.Add(null); -- Thrift does not allow null values in containers
foreach (var entry in value)
if( entry != null)
@@ -344,7 +347,7 @@
return value;
}
- private static Dictionary<Distance, Distance> ModifyValue(Dictionary<Distance, Distance> value)
+ private static Dictionary<Distance, Distance> ModifyValue(Dictionary<Distance, Distance>? value)
{
if (value == null)
value = new Dictionary<Distance, Distance>();
@@ -354,10 +357,10 @@
return value;
}
- private static THashSet<Distance> ModifyValue(THashSet<Distance> value)
+ private static HashSet<Distance> ModifyValue(HashSet<Distance>? value)
{
if (value == null)
- value = new THashSet<Distance>();
+ value = new HashSet<Distance>();
if (value.Contains(Distance.foo))
value.Remove(Distance.foo);
@@ -377,7 +380,7 @@
return value;
}
- private static List<Distance> ModifyValue(List<Distance> value)
+ private static List<Distance> ModifyValue(List<Distance>? value)
{
if (value == null)
value = new List<Distance>();
@@ -392,7 +395,7 @@
return !value;
}
- private static Dictionary<sbyte, short> ModifyValue(Dictionary<sbyte, short> value)
+ private static Dictionary<sbyte, short> ModifyValue(Dictionary<sbyte, short>? value)
{
if (value == null)
value = new Dictionary<sbyte, short>();
@@ -400,15 +403,15 @@
return value;
}
- private static THashSet<long> ModifyValue(THashSet<long> value)
+ private static HashSet<long> ModifyValue(HashSet<long>? value)
{
if (value == null)
- value = new THashSet<long>();
+ value = new HashSet<long>();
value.Add(value.Count+100);
return value;
}
- private static List<int> ModifyValue(List<int> value)
+ private static List<int> ModifyValue(List<int>? value)
{
if (value == null)
value = new List<int>();
@@ -416,16 +419,18 @@
return value;
}
- private static byte[] ModifyValue(byte[] value)
+ private static byte[] ModifyValue(byte[]? value)
{
if (value == null)
value = new byte[1] { 0 };
if (value.Length > 0)
value[0] = (value[0] < 0xFF) ? ++value[0] : (byte)0;
+ else
+ value = new byte[1] { 0 };
return value;
}
- private static string ModifyValue(string value)
+ private static string ModifyValue(string? value)
{
return value + "1";
}
diff --git a/lib/netstd/Tests/Thrift.Tests/DataModel/NullValuesSet.cs b/lib/netstd/Tests/Thrift.Tests/DataModel/NullValuesSet.cs
index 693b68e..ebc1717 100644
--- a/lib/netstd/Tests/Thrift.Tests/DataModel/NullValuesSet.cs
+++ b/lib/netstd/Tests/Thrift.Tests/DataModel/NullValuesSet.cs
@@ -25,13 +25,15 @@
using OptReqDefTest;
using Thrift.Collections;
+#pragma warning disable IDE0017 // init can be simplified - we don't want that here
+
namespace Thrift.Tests.DataModel
{
// ReSharper disable once InconsistentNaming
[TestClass]
public class Thrift_5238
{
- private void CheckInstance(RaceDetails instance)
+ private static void CheckInstance(RaceDetails instance)
{
// object
Assert.IsTrue(instance.__isset.def_nested);
@@ -42,14 +44,14 @@
// string
Assert.IsTrue(instance.__isset.def_four);
Assert.IsTrue(instance.__isset.opt_four);
- Assert.IsNull(instance.Req_four);
+ Assert.IsTrue(string.IsNullOrEmpty(instance.Req_four));
Assert.IsNull(instance.Def_four);
Assert.IsNull(instance.Opt_four);
// byte[]
Assert.IsTrue(instance.__isset.def_five);
Assert.IsTrue(instance.__isset.opt_five);
- Assert.IsNull(instance.Req_five);
+ Assert.IsTrue((instance.Req_five == null) || (instance.Req_five.Length == 0));
Assert.IsNull(instance.Def_five);
Assert.IsNull(instance.Opt_five);
@@ -66,6 +68,9 @@
{
var instance = new OptReqDefTest.RaceDetails();
+ // the following code INTENTIONALLY assigns null to non.nullable reftypes
+ #pragma warning disable CS8625
+
// object
instance.Def_nested = null;
instance.Opt_nested = null;
@@ -85,6 +90,9 @@
instance.Opt_six = null;
instance.Def_six = null;
+ // back to normal
+ #pragma warning restore CS8625
+
// test the setup
CheckInstance(instance);
diff --git a/lib/netstd/Tests/Thrift.Tests/Thrift.Tests.csproj b/lib/netstd/Tests/Thrift.Tests/Thrift.Tests.csproj
index 38a6a5c..27edf7b 100644
--- a/lib/netstd/Tests/Thrift.Tests/Thrift.Tests.csproj
+++ b/lib/netstd/Tests/Thrift.Tests/Thrift.Tests.csproj
@@ -20,7 +20,7 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
- <Version>0.16.0.0</Version>
+ <Version>0.17.0.0</Version>
<Nullable>enable</Nullable>
</PropertyGroup>
diff --git a/lib/netstd/Thrift/Collections/THashSet.cs b/lib/netstd/Thrift/Collections/THashSet.cs
index 1c060e5..fc2a507 100644
--- a/lib/netstd/Thrift/Collections/THashSet.cs
+++ b/lib/netstd/Thrift/Collections/THashSet.cs
@@ -15,69 +15,37 @@
// specific language governing permissions and limitations
// under the License.
+using System;
using System.Collections;
using System.Collections.Generic;
namespace Thrift.Collections
{
// ReSharper disable once InconsistentNaming
- public class THashSet<T> : ICollection<T>
+ [Obsolete("deprecated, use HashSet<T> instead")]
+ public class THashSet<T> : System.Collections.Generic.HashSet<T>
{
- private readonly HashSet<T> Items;
-
public THashSet()
+ : base()
{
- Items = new HashSet<T>();
}
public THashSet(int capacity)
+#if NET5_0_OR_GREATER
+ : base(capacity)
+#elif NETFRAMEWORK || NETSTANDARD
+ : base(/*capacity not supported*/)
+#else
+#error Unknown platform
+#endif
{
- #if NET5_0_OR_GREATER
- Items = new HashSet<T>(capacity);
- #elif NETFRAMEWORK || NETSTANDARD
- Items = new HashSet<T>(/*capacity not supported*/);
- #else
- #error Unknown platform
- #endif
}
- public int Count => Items.Count;
-
- public bool IsReadOnly => false;
-
- public void Add(T item)
+ public THashSet(IEnumerable<T> collection)
+ : base(collection)
{
- Items.Add(item);
}
- public void Clear()
- {
- Items.Clear();
- }
-
- public bool Contains(T item)
- {
- return Items.Contains(item);
- }
-
- public void CopyTo(T[] array, int arrayIndex)
- {
- Items.CopyTo(array, arrayIndex);
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return Items.GetEnumerator();
- }
-
- public IEnumerator<T> GetEnumerator()
- {
- return ((IEnumerable<T>) Items).GetEnumerator();
- }
-
- public bool Remove(T item)
- {
- return Items.Remove(item);
- }
}
}
+
diff --git a/lib/netstd/Thrift/Properties/AssemblyInfo.cs b/lib/netstd/Thrift/Properties/AssemblyInfo.cs
index 50fa031..5aa368f 100644
--- a/lib/netstd/Thrift/Properties/AssemblyInfo.cs
+++ b/lib/netstd/Thrift/Properties/AssemblyInfo.cs
@@ -52,5 +52,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
-[assembly: AssemblyVersion("0.16.0.0")]
-[assembly: AssemblyFileVersion("0.16.0.0")]
+[assembly: AssemblyVersion("0.17.0.0")]
+[assembly: AssemblyFileVersion("0.17.0.0")]
diff --git a/lib/netstd/Thrift/Thrift.csproj b/lib/netstd/Thrift/Thrift.csproj
index 162f475..cf06452 100644
--- a/lib/netstd/Thrift/Thrift.csproj
+++ b/lib/netstd/Thrift/Thrift.csproj
@@ -40,8 +40,8 @@
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>thrift.snk</AssemblyOriginatorKeyFile>
<DelaySign>false</DelaySign>
- <Title>Apache Thrift 0.16.0</Title>
- <Version>0.16.0.0</Version>
+ <Title>Apache Thrift 0.17.0</Title>
+ <Version>0.17.0.0</Version>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<PackageProjectUrl>http://thrift.apache.org/</PackageProjectUrl>
<Authors>Apache Thrift Developers</Authors>
@@ -50,7 +50,7 @@
<PackageDescription>C# .NET Core bindings for the Apache Thrift RPC system</PackageDescription>
<PackageReleaseNotes></PackageReleaseNotes>
<PackageTags>Apache Thrift RPC</PackageTags>
- <PackageReleaseNotes>https://github.com/apache/thrift/blob/0.16.0/CHANGES.md</PackageReleaseNotes>
+ <PackageReleaseNotes>https://github.com/apache/thrift/blob/0.17.0/CHANGES.md</PackageReleaseNotes>
<Copyright>Copyright 2022 The Apache Software Foundation</Copyright>
</PropertyGroup>
diff --git a/lib/netstd/Thrift/Transport/Client/TStreamTransport.cs b/lib/netstd/Thrift/Transport/Client/TStreamTransport.cs
index 90794c6..053a37b 100644
--- a/lib/netstd/Thrift/Transport/Client/TStreamTransport.cs
+++ b/lib/netstd/Thrift/Transport/Client/TStreamTransport.cs
@@ -80,11 +80,8 @@
"Cannot read from null inputstream");
}
-#if NETSTANDARD2_0
- return await InputStream.ReadAsync(buffer, offset, length, cancellationToken);
-#else
- return await InputStream.ReadAsync(new Memory<byte>(buffer, offset, length), cancellationToken);
-#endif
+ // The ReadAsync method should not be used since it does not check the ReceiveTimeout property.
+ return await Task.Run( () => InputStream.Read( buffer, offset, length ), cancellationToken );
}
public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken)
@@ -95,11 +92,8 @@
"Cannot write to null outputstream");
}
-#if NETSTANDARD2_0
- await OutputStream.WriteAsync(buffer, offset, length, cancellationToken);
-#else
- await OutputStream.WriteAsync(buffer.AsMemory(offset, length), cancellationToken);
-#endif
+ // The WriteAsync method should not be used since it does not check the SendTimeout property.
+ await Task.Run( () => OutputStream.Write( buffer, offset, length ), cancellationToken );
}
public override async Task FlushAsync(CancellationToken cancellationToken)
diff --git a/lib/ocaml/_oasis b/lib/ocaml/_oasis
index e901466..56374e0 100644
--- a/lib/ocaml/_oasis
+++ b/lib/ocaml/_oasis
@@ -1,5 +1,5 @@
Name: libthrift-ocaml
-Version: 0.16.0
+Version: 0.17.0
OASISFormat: 0.3
Synopsis: OCaml bindings for the Apache Thrift RPC system
Authors: Apache Thrift Developers <dev@thrift.apache.org>
diff --git a/lib/perl/lib/Thrift.pm b/lib/perl/lib/Thrift.pm
index b04cd21..e7e1f0c 100644
--- a/lib/perl/lib/Thrift.pm
+++ b/lib/perl/lib/Thrift.pm
@@ -31,6 +31,6 @@
#
package Thrift;
-use version 0.77; our $VERSION = version->declare("v0.16.0");
+use version 0.77; our $VERSION = version->declare("v0.17.0");
1;
diff --git a/lib/py/setup.py b/lib/py/setup.py
index 7cd4a2e..bba69c8 100644
--- a/lib/py/setup.py
+++ b/lib/py/setup.py
@@ -105,7 +105,7 @@
twisted_deps = ['twisted']
setup(name='thrift',
- version='0.16.0',
+ version='0.17.0',
description='Python bindings for the Apache Thrift RPC system',
long_description=read_file("README.md"),
long_description_content_type="text/markdown",
diff --git a/lib/py/src/ext/endian.h b/lib/py/src/ext/endian.h
index 1660cbd..a2cf594 100644
--- a/lib/py/src/ext/endian.h
+++ b/lib/py/src/ext/endian.h
@@ -25,7 +25,7 @@
#ifndef _WIN32
#include <netinet/in.h>
#else
-#include <WinSock2.h>
+#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#define BIG_ENDIAN (4321)
#define LITTLE_ENDIAN (1234)
diff --git a/lib/py/src/transport/THttpClient.py b/lib/py/src/transport/THttpClient.py
index 212da3a..b131690 100644
--- a/lib/py/src/transport/THttpClient.py
+++ b/lib/py/src/transport/THttpClient.py
@@ -98,7 +98,7 @@
return None
ap = "%s:%s" % (urllib.parse.unquote(proxy.username),
urllib.parse.unquote(proxy.password))
- cr = base64.b64encode(ap).strip()
+ cr = base64.b64encode(ap.encode()).strip()
return "Basic " + cr
def using_proxy(self):
diff --git a/lib/rb/thrift.gemspec b/lib/rb/thrift.gemspec
index 26fa86b..150b959 100644
--- a/lib/rb/thrift.gemspec
+++ b/lib/rb/thrift.gemspec
@@ -3,7 +3,7 @@
Gem::Specification.new do |s|
s.name = 'thrift'
- s.version = '0.16.0'
+ s.version = '0.17.0'
s.authors = ['Apache Thrift Developers']
s.email = ['dev@thrift.apache.org']
s.homepage = 'http://thrift.apache.org'
diff --git a/lib/rs/Cargo.toml b/lib/rs/Cargo.toml
index a32d671..4aedaec 100644
--- a/lib/rs/Cargo.toml
+++ b/lib/rs/Cargo.toml
@@ -2,7 +2,7 @@
name = "thrift"
description = "Rust bindings for the Apache Thrift RPC system"
edition = "2018"
-version = "0.16.0"
+version = "0.17.0"
license = "Apache-2.0"
authors = ["Apache Thrift Developers <dev@thrift.apache.org>"]
homepage = "http://thrift.apache.org"
diff --git a/lib/rs/src/protocol/binary.rs b/lib/rs/src/protocol/binary.rs
index 8509c34..9f8af43 100644
--- a/lib/rs/src/protocol/binary.rs
+++ b/lib/rs/src/protocol/binary.rs
@@ -84,7 +84,7 @@
// the thrift version header is intentionally negative
// so the first check we'll do is see if the sign bit is set
// and if so - assume it's the protocol-version header
- if first_bytes[0] >= 8 {
+ if (first_bytes[0] & 0x80) != 0 {
// apparently we got a protocol-version header - check
// it, and if it matches, read the rest of the fields
if first_bytes[0..2] != [0x80, 0x01] {
diff --git a/lib/st/package.xml b/lib/st/package.xml
index 134dff2..70cf0ac 100644
--- a/lib/st/package.xml
+++ b/lib/st/package.xml
@@ -17,7 +17,7 @@
specific language governing permissions and limitations
under the License.
-->
-<!-- Apache Thrift Smalltalk library version 0.16.0 -->
+<!-- Apache Thrift Smalltalk library version 0.17.0 -->
<package>
<name>libthrift-st</name>
<file>thrift.st</file>
diff --git a/lib/swift/Sources/Thrift.swift b/lib/swift/Sources/Thrift.swift
index e9be5ee..82b0421 100644
--- a/lib/swift/Sources/Thrift.swift
+++ b/lib/swift/Sources/Thrift.swift
@@ -1,3 +1,3 @@
class Thrift {
- let version = "0.16.0"
+ let version = "0.17.0"
}
diff --git a/lib/swift/Tests/ThriftTests/ThriftTests.swift b/lib/swift/Tests/ThriftTests/ThriftTests.swift
index 91a43ee..d19c89d 100644
--- a/lib/swift/Tests/ThriftTests/ThriftTests.swift
+++ b/lib/swift/Tests/ThriftTests/ThriftTests.swift
@@ -3,7 +3,7 @@
class ThriftTests: XCTestCase {
func testVersion() {
- XCTAssertEqual(Thrift().version, "0.16.0")
+ XCTAssertEqual(Thrift().version, "0.17.0")
}
static var allTests : [(String, (ThriftTests) -> () throws -> Void)] {
diff --git a/lib/ts/package-lock.json b/lib/ts/package-lock.json
index 041589b..19658c1 100644
--- a/lib/ts/package-lock.json
+++ b/lib/ts/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "thrift",
- "version": "0.16.0",
+ "version": "0.17.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/lib/ts/package.json b/lib/ts/package.json
index 268d0c6..8a564c6 100644
--- a/lib/ts/package.json
+++ b/lib/ts/package.json
@@ -1,6 +1,6 @@
{
"name": "thrift",
- "version": "0.16.0",
+ "version": "0.17.0",
"description": "Thrift is a software framework for scalable cross-language services development.",
"author": {
"name": "Apache Thrift Developers",
diff --git a/package-lock.json b/package-lock.json
index 1c8b2ae..161b8fe 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "thrift",
- "version": "0.16.0",
+ "version": "0.17.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 4ea721e..8f2e1c8 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,7 @@
"type": "git",
"url": "https://github.com/apache/thrift.git"
},
- "version": "0.16.0",
+ "version": "0.17.0",
"author": {
"name": "Apache Thrift Developers",
"email": "dev@thrift.apache.org",
diff --git a/sonar-project.properties b/sonar-project.properties
index 6c6c8f2..08d4c4a 100755
--- a/sonar-project.properties
+++ b/sonar-project.properties
@@ -16,7 +16,7 @@
services that work efficiently and seamlessly between all major languages.
# Apache Thrift Version
-sonar.projectVersion=0.16.0
+sonar.projectVersion=0.17.0
# use this to set another version string
# $ sonar-runner -D sonar.projectVersion=`git rev-parse HEAD`
# set projectDate in combination with projectVersion for imports of old releases
@@ -54,7 +54,7 @@
module1.sonar.projectBaseDir=lib/java
module1.sonar.sources=src
module1.sonar.tests=test
-module1.sonar.binaries=build/libs/libthrift-0.16.0.jar
+module1.sonar.binaries=build/libs/libthrift-0.17.0.jar
module1.sonar.libraries=build/deps/*.jar
module1.sonar.language=java
@@ -62,7 +62,7 @@
module2.sonar.projectBaseDir=.
module2.sonar.sources=tutorial/java/src, tutorial/java/gen-java
module2.sonar.binaries=tutorial/java/tutorial.jar
-module2.sonar.libraries=lib/java/build/deps/*.jar,lib/java/build/libs/libthrift-0.16.0.jar
+module2.sonar.libraries=lib/java/build/deps/*.jar,lib/java/build/libs/libthrift-0.17.0.jar
module2.sonar.language=java
module3.sonar.projectName=Apache Thrift - JavaScript Library
diff --git a/test/Makefile.am b/test/Makefile.am
index b289e53..2199f1e 100755
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -167,6 +167,7 @@
UnsafeTypes.thrift \
Service.thrift \
SpecificNameTest.thrift \
+ partial/thrift_test_schema.thrift \
known_failures_Linux.json \
test.py \
tests.json \
diff --git a/test/dart/test_client/pubspec.yaml b/test/dart/test_client/pubspec.yaml
index d5848b4..2898169 100644
--- a/test/dart/test_client/pubspec.yaml
+++ b/test/dart/test_client/pubspec.yaml
@@ -16,7 +16,7 @@
# under the License.
name: thrift_test_client
-version: 0.16.0
+version: 0.17.0
description: A client integration test for the Dart Thrift library
author: Apache Thrift Developers <dev@thrift.apache.org>
homepage: http://thrift.apache.org
diff --git a/test/erl/src/thrift_test.app.src b/test/erl/src/thrift_test.app.src
index 6faa1b5..60f7f14 100644
--- a/test/erl/src/thrift_test.app.src
+++ b/test/erl/src/thrift_test.app.src
@@ -22,7 +22,7 @@
{description, "Thrift cross language test"},
% The version of the applicaton
- {vsn, "0.16.0"},
+ {vsn, "0.17.0"},
% All modules used by the application.
{modules, [
diff --git a/test/netstd/Client/Client.csproj b/test/netstd/Client/Client.csproj
index 859297f..9d4ab48 100644
--- a/test/netstd/Client/Client.csproj
+++ b/test/netstd/Client/Client.csproj
@@ -24,7 +24,7 @@
<AssemblyName>Client</AssemblyName>
<PackageId>Client</PackageId>
<OutputType>Exe</OutputType>
- <Version>0.16.0.0</Version>
+ <Version>0.17.0.0</Version>
<GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
<GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
@@ -49,8 +49,8 @@
<Exec Condition="'$(OS)' == 'Windows_NT'" Command="where thrift" ConsoleToMSBuild="true">
<Output TaskParameter="ConsoleOutput" PropertyName="PathToThrift" />
</Exec>
- <Exec Condition="Exists('$(PathToThrift)')" Command=""$(PathToThrift)" -out $(ProjectDir) -gen netstd:wcf,union,serial -r ./../../ThriftTest.thrift" />
- <Exec Condition="Exists('thrift')" Command="thrift -out $(ProjectDir) -gen netstd:wcf,union,serial -r ./../../ThriftTest.thrift" />
- <Exec Condition="Exists('$(ProjectDir)/../../../compiler/cpp/thrift')" Command="$(ProjectDir)/../../../compiler/cpp/thrift -out $(ProjectDir) -gen netstd:wcf,union,serial -r ./../../ThriftTest.thrift" />
+ <Exec Condition="Exists('$(PathToThrift)')" Command=""$(PathToThrift)" -out $(ProjectDir) -gen netstd:wcf,union,serial,net6 -r ./../../ThriftTest.thrift" />
+ <Exec Condition="Exists('thrift')" Command="thrift -out $(ProjectDir) -gen netstd:wcf,union,serial,net6 -r ./../../ThriftTest.thrift" />
+ <Exec Condition="Exists('$(ProjectDir)/../../../compiler/cpp/thrift')" Command="$(ProjectDir)/../../../compiler/cpp/thrift -out $(ProjectDir) -gen netstd:wcf,union,serial,net6 -r ./../../ThriftTest.thrift" />
</Target>
</Project>
diff --git a/test/netstd/Client/Performance/TestDataFactory.cs b/test/netstd/Client/Performance/TestDataFactory.cs
index 833947c..8dec3f3 100644
--- a/test/netstd/Client/Performance/TestDataFactory.cs
+++ b/test/netstd/Client/Performance/TestDataFactory.cs
@@ -40,9 +40,9 @@
};
}
- private static THashSet<Insanity> CreateSetField(int count)
+ private static HashSet<Insanity> CreateSetField(int count)
{
- var retval = new THashSet<Insanity>();
+ var retval = new HashSet<Insanity>();
for (var i = 0; i < count; ++i)
retval.Add(CreateInsanity(count));
return retval;
@@ -90,41 +90,41 @@
return retval;
}
- private static List<Dictionary<THashSet<int>, Dictionary<int, THashSet<List<Dictionary<Insanity, string>>>>>> CreateListField(int count)
+ private static List<Dictionary<HashSet<int>, Dictionary<int, HashSet<List<Dictionary<Insanity, string>>>>>> CreateListField(int count)
{
- var retval = new List<Dictionary<THashSet<int>, Dictionary<int, THashSet<List<Dictionary<Insanity, string>>>>>>();
+ var retval = new List<Dictionary<HashSet<int>, Dictionary<int, HashSet<List<Dictionary<Insanity, string>>>>>>();
for (var i = 0; i < count; ++i)
retval.Add(CreateListFieldData(count));
return retval;
}
- private static Dictionary<THashSet<int>, Dictionary<int, THashSet<List<Dictionary<Insanity, string>>>>> CreateListFieldData(int count)
+ private static Dictionary<HashSet<int>, Dictionary<int, HashSet<List<Dictionary<Insanity, string>>>>> CreateListFieldData(int count)
{
- var retval = new Dictionary<THashSet<int>, Dictionary<int, THashSet<List<Dictionary<Insanity, string>>>>>();
+ var retval = new Dictionary<HashSet<int>, Dictionary<int, HashSet<List<Dictionary<Insanity, string>>>>>();
for (var i = 0; i < count; ++i)
retval.Add( CreateIntHashSet(count), CreateListFieldDataDict(count));
return retval;
}
- private static THashSet<int> CreateIntHashSet(int count)
+ private static HashSet<int> CreateIntHashSet(int count)
{
- var retval = new THashSet<int>();
+ var retval = new HashSet<int>();
for (var i = 0; i < count; ++i)
retval.Add(i);
return retval;
}
- private static Dictionary<int, THashSet<List<Dictionary<Insanity, string>>>> CreateListFieldDataDict(int count)
+ private static Dictionary<int, HashSet<List<Dictionary<Insanity, string>>>> CreateListFieldDataDict(int count)
{
- var retval = new Dictionary<int, THashSet<List<Dictionary<Insanity, string>>>>();
+ var retval = new Dictionary<int, HashSet<List<Dictionary<Insanity, string>>>>();
for (var i = 0; i < count; ++i)
retval.Add(i, CreateListFieldDataDictValue(count));
return retval;
}
- private static THashSet<List<Dictionary<Insanity, string>>> CreateListFieldDataDictValue(int count)
+ private static HashSet<List<Dictionary<Insanity, string>>> CreateListFieldDataDictValue(int count)
{
- var retval = new THashSet<List<Dictionary<Insanity, string>>>();
+ var retval = new HashSet<List<Dictionary<Insanity, string>>>();
for (var i = 0; i < count; ++i)
retval.Add( CreateListFieldDataDictValueList(count));
return retval;
diff --git a/test/netstd/Client/TestClient.cs b/test/netstd/Client/TestClient.cs
index 0a7fa00..29c0d2e 100644
--- a/test/netstd/Client/TestClient.cs
+++ b/test/netstd/Client/TestClient.cs
@@ -411,15 +411,28 @@
return ErrorUnknown;
}
- var tests = Enumerable.Range(0, param.numThreads).Select(_ => new ClientTest(param)).ToArray();
-
//issue tests on separate threads simultaneously
+ var nThreads = Math.Max(param.numThreads, 1);
+ Console.Write("Starting {0} test thread(s) ", nThreads);
+ var tasks = new Task[nThreads];
var start = DateTime.Now;
- var tasks = tests.Select(test => test.Execute()).ToArray();
+ var retcode = 0;
+ for (var i = 0; i < tasks.Length; ++i)
+ {
+ Console.Write('.');
+ tasks[i] = Task.Run(async () =>
+ {
+ var test = new ClientTest(param);
+ await test.Execute();
+ lock (tasks)
+ retcode |= test.ReturnCode;
+ });
+ }
+ Console.WriteLine(" OK");
Task.WaitAll(tasks);
Console.WriteLine("Total time: " + (DateTime.Now - start));
Console.WriteLine();
- return tests.Select(t => t.ReturnCode).Aggregate((r1, r2) => r1 | r2);
+ return retcode;
}
catch (Exception outerEx)
{
@@ -490,7 +503,7 @@
return retval;
}
- private static CancellationToken MakeTimeoutToken(int msec = 5000)
+ private static CancellationToken MakeTimeoutToken(int msec = 15_000)
{
var token = new CancellationTokenSource(msec);
return token.Token;
@@ -644,9 +657,14 @@
Struct_thing = o,
I32_thing = 5
};
- var i2 = await client.testNest(o2, MakeTimeoutToken());
+ Xtruct2 i2 = await client.testNest(o2, MakeTimeoutToken());
i = i2.Struct_thing;
- Console.WriteLine(" = {" + i2.Byte_thing + ", {\"" + i.String_thing + "\", " + i.Byte_thing + ", " + i.I32_thing + ", " + i.I64_thing + "}, " + i2.I32_thing + "}");
+ Console.WriteLine(" = {" + i2.Byte_thing + ", {\""
+ + (i?.String_thing ?? "<null>") + "\", "
+ + (i?.Byte_thing ?? 0) + ", "
+ + (i?.I32_thing ?? 0) + ", "
+ + (i?.I64_thing ?? 0) + "}, "
+ + i2.I32_thing + "}");
var mapout = new Dictionary<int, int>();
for (var j = 0; j < 5; j++)
@@ -681,7 +699,7 @@
//set
// TODO: Validate received message
- var setout = new THashSet<int>();
+ var setout = new HashSet<int>();
for (var j = -2; j < 3; j++)
{
setout.Add(j);
@@ -937,7 +955,7 @@
}
catch (Xception2 ex)
{
- if (ex.ErrorCode != 2002 || ex.Struct_thing.String_thing != "This is an Xception2")
+ if (ex.ErrorCode != 2002 || ex.Struct_thing?.String_thing != "This is an Xception2")
{
Console.WriteLine("*** FAILED ***");
returnCode |= ErrorExceptions;
diff --git a/test/netstd/Server/Server.csproj b/test/netstd/Server/Server.csproj
index cda1dff..439e5c1 100644
--- a/test/netstd/Server/Server.csproj
+++ b/test/netstd/Server/Server.csproj
@@ -24,7 +24,7 @@
<AssemblyName>Server</AssemblyName>
<PackageId>Server</PackageId>
<OutputType>Exe</OutputType>
- <Version>0.16.0.0</Version>
+ <Version>0.17.0.0</Version>
<GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
<GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
@@ -51,8 +51,8 @@
<Exec Condition="'$(OS)' == 'Windows_NT'" Command="where thrift" ConsoleToMSBuild="true">
<Output TaskParameter="ConsoleOutput" PropertyName="PathToThrift" />
</Exec>
- <Exec Condition="Exists('$(PathToThrift)')" Command=""$(PathToThrift)" -out $(ProjectDir) -gen netstd:wcf,union,serial -r ./../../ThriftTest.thrift" />
- <Exec Condition="Exists('thrift')" Command="thrift -out $(ProjectDir) -gen netstd:wcf,union,serial -r ./../../ThriftTest.thrift" />
- <Exec Condition="Exists('$(ProjectDir)/../../../compiler/cpp/thrift')" Command="$(ProjectDir)/../../../compiler/cpp/thrift -out $(ProjectDir) -gen netstd:wcf,union,serial -r ./../../ThriftTest.thrift" />
+ <Exec Condition="Exists('$(PathToThrift)')" Command=""$(PathToThrift)" -out $(ProjectDir) -gen netstd:wcf,union,serial,net6 -r ./../../ThriftTest.thrift" />
+ <Exec Condition="Exists('thrift')" Command="thrift -out $(ProjectDir) -gen netstd:wcf,union,serial,net6 -r ./../../ThriftTest.thrift" />
+ <Exec Condition="Exists('$(ProjectDir)/../../../compiler/cpp/thrift')" Command="$(ProjectDir)/../../../compiler/cpp/thrift -out $(ProjectDir) -gen netstd:wcf,union,serial,net6 -r ./../../ThriftTest.thrift" />
</Target>
</Project>
diff --git a/test/netstd/Server/TestServer.cs b/test/netstd/Server/TestServer.cs
index 515a299..86072b0 100644
--- a/test/netstd/Server/TestServer.cs
+++ b/test/netstd/Server/TestServer.cs
@@ -229,10 +229,10 @@
return Task.CompletedTask;
}
- public Task<string> testString(string thing, CancellationToken cancellationToken)
+ public Task<string> testString(string? thing, CancellationToken cancellationToken)
{
- logger.Invoke("testString({0})", thing);
- return Task.FromResult(thing);
+ logger.Invoke("testString({0})", thing ?? "<null>");
+ return Task.FromResult(thing ?? string.Empty);
}
public Task<bool> testBool(bool thing, CancellationToken cancellationToken)
@@ -265,117 +265,129 @@
return Task.FromResult(thing);
}
- public Task<byte[]> testBinary(byte[] thing, CancellationToken cancellationToken)
+ public Task<byte[]> testBinary(byte[]? thing, CancellationToken cancellationToken)
{
- logger.Invoke("testBinary({0} bytes)", thing.Length);
- return Task.FromResult(thing);
+ logger.Invoke("testBinary({0} bytes)", thing?.Length ?? 0);
+ return Task.FromResult(thing ?? Array.Empty<byte>());
}
- public Task<Xtruct> testStruct(Xtruct thing, CancellationToken cancellationToken)
+ public Task<Xtruct> testStruct(Xtruct? thing, CancellationToken cancellationToken)
{
- logger.Invoke("testStruct({{\"{0}\", {1}, {2}, {3}}})", thing.String_thing, thing.Byte_thing, thing.I32_thing, thing.I64_thing);
- return Task.FromResult(thing);
+ logger.Invoke("testStruct({{\"{0}\", {1}, {2}, {3}}})", thing?.String_thing ?? "<null>", thing?.Byte_thing ?? 0, thing?.I32_thing ?? 0, thing?.I64_thing ?? 0);
+ return Task.FromResult(thing ?? new Xtruct()); // null returns are not allowed in Thrift
}
- public Task<Xtruct2> testNest(Xtruct2 nest, CancellationToken cancellationToken)
+ public Task<Xtruct2> testNest(Xtruct2? nest, CancellationToken cancellationToken)
{
- var thing = nest.Struct_thing;
+ var thing = nest?.Struct_thing;
logger.Invoke("testNest({{{0}, {{\"{1}\", {2}, {3}, {4}, {5}}}}})",
- nest.Byte_thing,
- thing.String_thing,
- thing.Byte_thing,
- thing.I32_thing,
- thing.I64_thing,
- nest.I32_thing);
- return Task.FromResult(nest);
+ nest?.Byte_thing ?? 0,
+ thing?.String_thing ?? "<null>",
+ thing?.Byte_thing ?? 0,
+ thing?.I32_thing ?? 0,
+ thing?.I64_thing ?? 0,
+ nest?.I32_thing ?? 0);
+ return Task.FromResult(nest ?? new Xtruct2()); // null returns are not allowed in Thrift
}
- public Task<Dictionary<int, int>> testMap(Dictionary<int, int> thing, CancellationToken cancellationToken)
+ public Task<Dictionary<int, int>> testMap(Dictionary<int, int>? thing, CancellationToken cancellationToken)
{
sb.Clear();
sb.Append("testMap({{");
- var first = true;
- foreach (var key in thing.Keys)
+ if (thing != null)
{
- if (first)
+ var first = true;
+ foreach (var key in thing.Keys)
{
- first = false;
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ sb.Append(", ");
+ }
+ sb.AppendFormat("{0} => {1}", key, thing[key]);
}
- else
- {
- sb.Append(", ");
- }
- sb.AppendFormat("{0} => {1}", key, thing[key]);
}
sb.Append("}})");
logger.Invoke(sb.ToString());
- return Task.FromResult(thing);
+ return Task.FromResult(thing ?? new Dictionary<int, int>()); // null returns are not allowed in Thrift
}
- public Task<Dictionary<string, string>> testStringMap(Dictionary<string, string> thing, CancellationToken cancellationToken)
+ public Task<Dictionary<string, string>> testStringMap(Dictionary<string, string>? thing, CancellationToken cancellationToken)
{
sb.Clear();
sb.Append("testStringMap({{");
- var first = true;
- foreach (var key in thing.Keys)
+ if (thing != null)
{
- if (first)
+ var first = true;
+ foreach (var key in thing.Keys)
{
- first = false;
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ sb.Append(", ");
+ }
+ sb.AppendFormat("{0} => {1}", key, thing[key]);
}
- else
- {
- sb.Append(", ");
- }
- sb.AppendFormat("{0} => {1}", key, thing[key]);
}
sb.Append("}})");
logger.Invoke(sb.ToString());
- return Task.FromResult(thing);
+ return Task.FromResult(thing ?? new Dictionary<string, string>()); // null returns are not allowed in Thrift
}
- public Task<THashSet<int>> testSet(THashSet<int> thing, CancellationToken cancellationToken)
+ public Task<HashSet<int>> testSet(HashSet<int>? thing, CancellationToken cancellationToken)
{
sb.Clear();
sb.Append("testSet({{");
- var first = true;
- foreach (int elem in thing)
+ if (thing != null)
{
- if (first)
+ var first = true;
+ foreach (int elem in thing)
{
- first = false;
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ sb.Append(", ");
+ }
+ sb.AppendFormat("{0}", elem);
}
- else
- {
- sb.Append(", ");
- }
- sb.AppendFormat("{0}", elem);
}
sb.Append("}})");
logger.Invoke(sb.ToString());
- return Task.FromResult(thing);
+ return Task.FromResult(thing ?? new HashSet<int>()); // null returns are not allowed in Thrift
}
- public Task<List<int>> testList(List<int> thing, CancellationToken cancellationToken)
+ public Task<List<int>> testList(List<int>? thing, CancellationToken cancellationToken)
{
sb.Clear();
sb.Append("testList({{");
- var first = true;
- foreach (var elem in thing)
+ if (thing != null)
{
- if (first)
+ var first = true;
+ foreach (var elem in thing)
{
- first = false;
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ sb.Append(", ");
+ }
+ sb.AppendFormat("{0}", elem);
}
- else
- {
- sb.Append(", ");
- }
- sb.AppendFormat("{0}", elem);
}
sb.Append("}})");
logger.Invoke(sb.ToString());
- return Task.FromResult(thing);
+ return Task.FromResult(thing ?? new List<int>()); // null returns are not allowed in Thrift
}
public Task<Numberz> testEnum(Numberz thing, CancellationToken cancellationToken)
@@ -409,7 +421,7 @@
return Task.FromResult(mapmap);
}
- public Task<Dictionary<long, Dictionary<Numberz, Insanity>>> testInsanity(Insanity argument, CancellationToken cancellationToken)
+ public Task<Dictionary<long, Dictionary<Numberz, Insanity>>> testInsanity(Insanity? argument, CancellationToken cancellationToken)
{
logger.Invoke("testInsanity()");
@@ -428,8 +440,9 @@
var first_map = new Dictionary<Numberz, Insanity>();
var second_map = new Dictionary<Numberz, Insanity>(); ;
- first_map[Numberz.TWO] = argument;
- first_map[Numberz.THREE] = argument;
+ // null dict keys/values are not allowed in Thrift
+ first_map[Numberz.TWO] = argument ?? new Insanity();
+ first_map[Numberz.THREE] = argument ?? new Insanity();
second_map[Numberz.SIX] = new Insanity();
@@ -442,7 +455,7 @@
return Task.FromResult(insane);
}
- public Task<Xtruct> testMulti(sbyte arg0, int arg1, long arg2, Dictionary<short, string> arg3, Numberz arg4, long arg5,
+ public Task<Xtruct> testMulti(sbyte arg0, int arg1, long arg2, Dictionary<short, string>? arg3, Numberz arg4, long arg5,
CancellationToken cancellationToken)
{
logger.Invoke("testMulti()");
@@ -455,9 +468,9 @@
return Task.FromResult(hello);
}
- public Task testException(string arg, CancellationToken cancellationToken)
+ public Task testException(string? arg, CancellationToken cancellationToken)
{
- logger.Invoke("testException({0})", arg);
+ logger.Invoke("testException({0})", arg ?? "<null>");
if (arg == "Xception")
{
var x = new Xception
@@ -474,9 +487,9 @@
return Task.CompletedTask;
}
- public Task<Xtruct> testMultiException(string arg0, string arg1, CancellationToken cancellationToken)
+ public Task<Xtruct> testMultiException(string? arg0, string? arg1, CancellationToken cancellationToken)
{
- logger.Invoke("testMultiException({0}, {1})", arg0, arg1);
+ logger.Invoke("testMultiException({0}, {1})", arg0 ?? "<null>", arg1 ?? "<null>");
if (arg0 == "Xception")
{
var x = new Xception
diff --git a/tutorial/dart/client/pubspec.yaml b/tutorial/dart/client/pubspec.yaml
index 465bd93..028f003 100644
--- a/tutorial/dart/client/pubspec.yaml
+++ b/tutorial/dart/client/pubspec.yaml
@@ -16,7 +16,7 @@
# under the License.
name: tutorial_client
-version: 0.16.0
+version: 0.17.0
description: A Dart client implementation of the Apache Thrift tutorial
author: Apache Thrift Developers <dev@thrift.apache.org>
homepage: http://thrift.apache.org
diff --git a/tutorial/dart/console_client/pubspec.yaml b/tutorial/dart/console_client/pubspec.yaml
index 9a8d202..435177f 100644
--- a/tutorial/dart/console_client/pubspec.yaml
+++ b/tutorial/dart/console_client/pubspec.yaml
@@ -16,7 +16,7 @@
# under the License.
name: tutorial_console_client
-version: 0.16.0
+version: 0.17.0
description: >
A Dart console client to implementation of the Apache Thrift tutorial
author: Apache Thrift Developers <dev@thrift.apache.org>
diff --git a/tutorial/dart/server/pubspec.yaml b/tutorial/dart/server/pubspec.yaml
index 17c4220..0590094 100644
--- a/tutorial/dart/server/pubspec.yaml
+++ b/tutorial/dart/server/pubspec.yaml
@@ -16,7 +16,7 @@
# under the License.
name: tutorial_server
-version: 0.16.0
+version: 0.17.0
description: A Dart server to support the Apache Thrift tutorial
author: Apache Thrift Developers <dev@thrift.apache.org>
homepage: http://thrift.apache.org
diff --git a/tutorial/delphi/DelphiClient/DelphiClient.dproj b/tutorial/delphi/DelphiClient/DelphiClient.dproj
index cc5170d..ec487e9 100644
--- a/tutorial/delphi/DelphiClient/DelphiClient.dproj
+++ b/tutorial/delphi/DelphiClient/DelphiClient.dproj
@@ -124,13 +124,13 @@
<VersionInfoKeys>
<VersionInfoKeys Name="CompanyName"/>
<VersionInfoKeys Name="FileDescription">Thrift Tutorial</VersionInfoKeys>
- <VersionInfoKeys Name="FileVersion">0.16.0.0</VersionInfoKeys>
+ <VersionInfoKeys Name="FileVersion">0.17.0.0</VersionInfoKeys>
<VersionInfoKeys Name="InternalName">DelphiClient</VersionInfoKeys>
<VersionInfoKeys Name="LegalCopyright">Copyright © 2012 The Apache Software Foundation</VersionInfoKeys>
<VersionInfoKeys Name="LegalTrademarks"/>
<VersionInfoKeys Name="OriginalFilename">DelphiClient.exe</VersionInfoKeys>
<VersionInfoKeys Name="ProductName">Thrift</VersionInfoKeys>
- <VersionInfoKeys Name="ProductVersion">0.16.0.0</VersionInfoKeys>
+ <VersionInfoKeys Name="ProductVersion">0.17.0.0</VersionInfoKeys>
<VersionInfoKeys Name="Comments"/>
</VersionInfoKeys>
<Source>
diff --git a/tutorial/delphi/DelphiServer/DelphiServer.dproj b/tutorial/delphi/DelphiServer/DelphiServer.dproj
index 82a2cee..31e8fd8 100644
--- a/tutorial/delphi/DelphiServer/DelphiServer.dproj
+++ b/tutorial/delphi/DelphiServer/DelphiServer.dproj
@@ -121,13 +121,13 @@
<VersionInfoKeys>
<VersionInfoKeys Name="CompanyName"/>
<VersionInfoKeys Name="FileDescription">Thrift Tutorial</VersionInfoKeys>
- <VersionInfoKeys Name="FileVersion">0.16.0.0</VersionInfoKeys>
+ <VersionInfoKeys Name="FileVersion">0.17.0.0</VersionInfoKeys>
<VersionInfoKeys Name="InternalName">DelphiServer</VersionInfoKeys>
<VersionInfoKeys Name="LegalCopyright">Copyright © 2012 The Apache Software Foundation</VersionInfoKeys>
<VersionInfoKeys Name="LegalTrademarks"/>
<VersionInfoKeys Name="OriginalFilename">DelphiServer.exe</VersionInfoKeys>
<VersionInfoKeys Name="ProductName">Thrift</VersionInfoKeys>
- <VersionInfoKeys Name="ProductVersion">0.16.0.0</VersionInfoKeys>
+ <VersionInfoKeys Name="ProductVersion">0.17.0.0</VersionInfoKeys>
<VersionInfoKeys Name="Comments"/>
</VersionInfoKeys>
<Source>
diff --git a/tutorial/netstd/Client/Client.csproj b/tutorial/netstd/Client/Client.csproj
index cf01951..158e592 100644
--- a/tutorial/netstd/Client/Client.csproj
+++ b/tutorial/netstd/Client/Client.csproj
@@ -24,7 +24,7 @@
<AssemblyName>Client</AssemblyName>
<PackageId>Client</PackageId>
<OutputType>Exe</OutputType>
- <Version>0.16.0.0</Version>
+ <Version>0.17.0.0</Version>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
diff --git a/tutorial/netstd/Interfaces/Interfaces.csproj b/tutorial/netstd/Interfaces/Interfaces.csproj
index a288745..d04b243 100644
--- a/tutorial/netstd/Interfaces/Interfaces.csproj
+++ b/tutorial/netstd/Interfaces/Interfaces.csproj
@@ -22,7 +22,7 @@
<TargetFramework>net6.0</TargetFramework>
<AssemblyName>Interfaces</AssemblyName>
<PackageId>Interfaces</PackageId>
- <Version>0.16.0.0</Version>
+ <Version>0.17.0.0</Version>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
@@ -41,8 +41,8 @@
<Exec Condition="'$(OS)' == 'Windows_NT'" Command="where thrift" ConsoleToMSBuild="true">
<Output TaskParameter="ConsoleOutput" PropertyName="PathToThrift" />
</Exec>
- <Exec Condition="Exists('$(PathToThrift)')" Command="$(PathToThrift) -out $(ProjectDir) -gen netstd:wcf,union,serial -r ./../../tutorial.thrift" />
- <Exec Condition="Exists('thrift')" Command="thrift -out $(ProjectDir) -gen netstd:wcf,union,serial -r ./../../tutorial.thrift" />
- <Exec Condition="Exists('./../../../compiler/cpp/thrift')" Command="./../../../compiler/cpp/thrift -out $(ProjectDir) -gen netstd:wcf,union,serial -r ./../../tutorial.thrift" />
+ <Exec Condition="Exists('$(PathToThrift)')" Command="$(PathToThrift) -out $(ProjectDir) -gen netstd:wcf,union,serial,net6 -r ./../../tutorial.thrift" />
+ <Exec Condition="Exists('thrift')" Command="thrift -out $(ProjectDir) -gen netstd:wcf,union,serial,net6 -r ./../../tutorial.thrift" />
+ <Exec Condition="Exists('./../../../compiler/cpp/thrift')" Command="./../../../compiler/cpp/thrift -out $(ProjectDir) -gen netstd:wcf,union,serial,net6 -r ./../../tutorial.thrift" />
</Target>
</Project>
diff --git a/tutorial/netstd/Server/Program.cs b/tutorial/netstd/Server/Program.cs
index d9c9dbf..29b21d0 100644
--- a/tutorial/netstd/Server/Program.cs
+++ b/tutorial/netstd/Server/Program.cs
@@ -131,7 +131,7 @@
if (selectedTransport == Transport.Http)
{
if (multiplex)
- throw new Exception("This tutorial semple code does not yet allow multiplex over http (although Thrift itself of course does)");
+ throw new Exception("This tutorial sample code does not yet allow multiplex over http (although Thrift itself of course does)");
new HttpServerSample().Run(cancellationToken);
}
else
diff --git a/tutorial/netstd/Server/Server.csproj b/tutorial/netstd/Server/Server.csproj
index 6bee63f..cf11a75 100644
--- a/tutorial/netstd/Server/Server.csproj
+++ b/tutorial/netstd/Server/Server.csproj
@@ -24,7 +24,7 @@
<AssemblyName>Server</AssemblyName>
<PackageId>Server</PackageId>
<OutputType>Exe</OutputType>
- <Version>0.16.0.0</Version>
+ <Version>0.17.0.0</Version>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
diff --git a/tutorial/ocaml/_oasis b/tutorial/ocaml/_oasis
index 5a98ccd..9e211fc 100644
--- a/tutorial/ocaml/_oasis
+++ b/tutorial/ocaml/_oasis
@@ -1,5 +1,5 @@
Name: tutorial
-Version: 0.16.0
+Version: 0.17.0
OASISFormat: 0.3
Synopsis: OCaml Tutorial example
Authors: Apache Thrift Developers <dev@thrift.apache.org>