THRIFT-5511 Full support for the new net6 "nullability" semantics

Client: netstd
Patch: Jens Geyer

This closes #2516
This commit is contained in:
Jens Geyer 2022-01-31 18:04:35 +01:00
parent 2d667f3476
commit 3cac320451
16 changed files with 717 additions and 407 deletions

File diff suppressed because it is too large Load Diff

View File

@ -116,7 +116,7 @@ public:
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 @@ public:
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);
@ -152,15 +152,19 @@ public:
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 @@ private:
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 @@ private:
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
};

View File

@ -26,30 +26,30 @@ namespace Thrift.PublicInterfaces.Compile.Tests.Impl.Thrift5253
{
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 @@ namespace Thrift.PublicInterfaces.Compile.Tests.Impl.Thrift5253
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 });
}
}
}

View File

@ -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>

View File

@ -83,8 +83,8 @@ namespace Thrift.Tests.Collections
[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 @@ namespace Thrift.Tests.Collections
[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 @@ namespace Thrift.Tests.Collections
[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 @@ namespace Thrift.Tests.Collections
[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 @@ namespace Thrift.Tests.Collections
[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));

View File

@ -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 System.Text;
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 @@ namespace Thrift.Tests.Collections
{
const int value = 1;
var hashSet = new THashSet<int> {value};
var hashSet = new HashSet<int> {value};
Assert.IsTrue(hashSet.Contains(value));

View File

@ -24,8 +24,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
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 @@ namespace Thrift.Tests.DataModel
VerifyIdenticalContent(first, InitializeInstance(new RaceDetails()));
}
private RaceDetails MakeNestedRaceDetails(int nesting)
private RaceDetails? MakeNestedRaceDetails(int nesting)
{
if (++nesting > 1)
return null;
@ -61,7 +59,7 @@ namespace Thrift.Tests.DataModel
return instance;
}
private jack MakeNestedUnion(int nesting)
private jack? MakeNestedUnion(int nesting)
{
if (++nesting > 1)
return null;
@ -88,11 +86,11 @@ namespace Thrift.Tests.DataModel
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 @@ namespace Thrift.Tests.DataModel
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 @@ namespace Thrift.Tests.DataModel
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 @@ namespace Thrift.Tests.DataModel
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 @@ namespace Thrift.Tests.DataModel
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 @@ namespace Thrift.Tests.DataModel
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 @@ namespace Thrift.Tests.DataModel
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 @@ namespace Thrift.Tests.DataModel
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 @@ namespace Thrift.Tests.DataModel
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 @@ namespace Thrift.Tests.DataModel
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 @@ namespace Thrift.Tests.DataModel
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 @@ namespace Thrift.Tests.DataModel
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 @@ namespace Thrift.Tests.DataModel
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";
}

View File

@ -25,13 +25,15 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
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 @@ namespace Thrift.Tests.DataModel
// 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 @@ namespace Thrift.Tests.DataModel
{
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 @@ namespace Thrift.Tests.DataModel
instance.Opt_six = null;
instance.Def_six = null;
// back to normal
#pragma warning restore CS8625
// test the setup
CheckInstance(instance);

View File

@ -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);
}
}
}

View File

@ -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="&quot;$(PathToThrift)&quot; -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="&quot;$(PathToThrift)&quot; -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>

View File

@ -40,9 +40,9 @@ namespace Client.Tests
};
}
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 @@ namespace Client.Tests
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;

View File

@ -644,9 +644,14 @@ namespace ThriftTest
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 +686,7 @@ namespace ThriftTest
//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 +942,7 @@ namespace ThriftTest
}
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;

View File

@ -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="&quot;$(PathToThrift)&quot; -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="&quot;$(PathToThrift)&quot; -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>

View File

@ -229,10 +229,10 @@ namespace ThriftTest
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 @@ namespace ThriftTest
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 @@ namespace ThriftTest
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 @@ namespace ThriftTest
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 @@ namespace ThriftTest
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 @@ namespace ThriftTest
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 @@ namespace ThriftTest
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

View File

@ -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>

View File

@ -131,7 +131,7 @@ Sample:
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