From e4ef4d1d0fab9ef51804006b451e6697ac8869a3 Mon Sep 17 00:00:00 2001 From: neuecc Date: Fri, 9 Oct 2020 08:35:34 +0900 Subject: [PATCH 01/18] typeless supports interface and abstract --- .../Formatters/TypelessFormatter.cs | 20 ++++++++++ .../TypelessContractlessStandardResolver.cs | 1 + .../Resolvers/TypelessObjectResolver.cs | 23 +++++++++++ .../MessagePackSerializerTypelessTests.cs | 40 +++++++++++++++++++ src/MessagePack/PublicAPI.Unshipped.txt | 9 +++++ 5 files changed, 93 insertions(+) diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/TypelessFormatter.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/TypelessFormatter.cs index 494a7d6cb..5c9c97c77 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/TypelessFormatter.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/TypelessFormatter.cs @@ -16,6 +16,26 @@ namespace MessagePack.Formatters { +#pragma warning disable SA1649 // File name should match first type name + + /// + /// Force serialize object as typeless. + /// + public sealed class ForceTypelessFormatter : IMessagePackFormatter + { + public void Serialize(ref MessagePackWriter writer, T value, MessagePackSerializerOptions options) + { + TypelessFormatter.Instance.Serialize(ref writer, (object)value, options); + } + + public T Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) + { + return (T)TypelessFormatter.Instance.Deserialize(ref reader, options); + } + } + +#pragma warning restore SA1649 // File name should match first type name + /// /// For `object` field that holds derived from `object` value, ex: var arr = new object[] { 1, "a", new Model() };. /// diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/TypelessContractlessStandardResolver.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/TypelessContractlessStandardResolver.cs index df789b9ef..1b3d9c4fc 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/TypelessContractlessStandardResolver.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/TypelessContractlessStandardResolver.cs @@ -41,6 +41,7 @@ public sealed class TypelessContractlessStandardResolver : IFormatterResolver DynamicUnionResolver.Instance, // Try Union(Interface) DynamicObjectResolver.Instance, // Try Object #endif + TypelessInterfaceObjectResolver.Instance, // can not serialize abstract/interface type on ContractlessResolver, hook before it. DynamicContractlessObjectResolverAllowPrivate.Instance, // Serializes keys as strings TypelessObjectResolver.Instance, }; diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/TypelessObjectResolver.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/TypelessObjectResolver.cs index cb670e089..36b3fdf02 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/TypelessObjectResolver.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/TypelessObjectResolver.cs @@ -55,6 +55,29 @@ public IMessagePackFormatter GetFormatter() } } + /// + /// Helper resolver for interface/abstract type which not implements Union attribute. + /// + public sealed class TypelessInterfaceObjectResolver : IFormatterResolver + { + public static readonly IFormatterResolver Instance = new TypelessInterfaceObjectResolver(); + + private TypelessInterfaceObjectResolver() + { + } + + /// + public IMessagePackFormatter GetFormatter() + { + if (typeof(T).IsAbstract || typeof(T).IsInterface) + { + return new ForceTypelessFormatter(); + } + + return null; + } + } + /* helpers for TypelessFormatter */ internal sealed class ForceSizePrimitiveObjectResolver : IFormatterResolver diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTypelessTests.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTypelessTests.cs index 081993347..4364ef90f 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTypelessTests.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTypelessTests.cs @@ -75,6 +75,19 @@ public void OmitAssemblyVersion() Assert.DoesNotContain(ThisAssembly.AssemblyVersion, json); } + [Fact] + public void SerializeInterface() + { + var v = new Holder() { T1 = new TypelessInterface { X = 999 }, T2 = new TypelessNonAbstract { X = 19, Y = 9999 } }; + var bin = MessagePackSerializer.Typeless.Serialize(v); + var v2 = MessagePackSerializer.Typeless.Deserialize(bin).IsInstanceOf(); + + v2.T1.IsInstanceOf().X.Is(999); + var t2 = v2.T2.IsInstanceOf(); + t2.X.Is(19); + t2.Y.Is(9999); + } + [Theory] [InlineData((sbyte)1)] [InlineData((byte)1)] @@ -125,6 +138,33 @@ public override void ThrowIfDeserializingTypeIsDisallowed(Type type) protected override MessagePackSerializerOptions Clone() => new MyTypelessOptions(this); } + + public class Holder + { + public ITypelessInterface T1 { get; set; } + + public TypelessAbstract T2 { get; set; } + } + + public interface ITypelessInterface + { + int X { get; } + } + + public class TypelessInterface : ITypelessInterface + { + public int X { get; set; } + } + + public abstract class TypelessAbstract + { + public int X { get; set; } + } + + public class TypelessNonAbstract : TypelessAbstract + { + public int Y { get; set; } + } } #endif diff --git a/src/MessagePack/PublicAPI.Unshipped.txt b/src/MessagePack/PublicAPI.Unshipped.txt index 5317a1687..c21a26704 100644 --- a/src/MessagePack/PublicAPI.Unshipped.txt +++ b/src/MessagePack/PublicAPI.Unshipped.txt @@ -10,6 +10,10 @@ MessagePack.Formatters.ByteReadOnlySequenceFormatter.Serialize(ref MessagePack.M MessagePack.Formatters.ExpandoObjectFormatter MessagePack.Formatters.ExpandoObjectFormatter.Deserialize(ref MessagePack.MessagePackReader reader, MessagePack.MessagePackSerializerOptions options) -> System.Dynamic.ExpandoObject MessagePack.Formatters.ExpandoObjectFormatter.Serialize(ref MessagePack.MessagePackWriter writer, System.Dynamic.ExpandoObject value, MessagePack.MessagePackSerializerOptions options) -> void +MessagePack.Formatters.ForceTypelessFormatter +MessagePack.Formatters.ForceTypelessFormatter.Deserialize(ref MessagePack.MessagePackReader reader, MessagePack.MessagePackSerializerOptions options) -> T +MessagePack.Formatters.ForceTypelessFormatter.ForceTypelessFormatter() -> void +MessagePack.Formatters.ForceTypelessFormatter.Serialize(ref MessagePack.MessagePackWriter writer, T value, MessagePack.MessagePackSerializerOptions options) -> void MessagePack.Formatters.MemoryFormatter MessagePack.Formatters.MemoryFormatter.Deserialize(ref MessagePack.MessagePackReader reader, MessagePack.MessagePackSerializerOptions options) -> System.Memory MessagePack.Formatters.MemoryFormatter.MemoryFormatter() -> void @@ -32,6 +36,8 @@ MessagePack.Formatters.ReadOnlySequenceFormatter.Serialize(ref MessagePack.Me MessagePack.Formatters.TypeFormatter MessagePack.Formatters.TypeFormatter.Deserialize(ref MessagePack.MessagePackReader reader, MessagePack.MessagePackSerializerOptions options) -> T MessagePack.Formatters.TypeFormatter.Serialize(ref MessagePack.MessagePackWriter writer, T value, MessagePack.MessagePackSerializerOptions options) -> void +MessagePack.Formatters.ValueTupleFormatter.Deserialize(ref MessagePack.MessagePackReader reader, MessagePack.MessagePackSerializerOptions options) -> ValueTuple +MessagePack.Formatters.ValueTupleFormatter.Serialize(ref MessagePack.MessagePackWriter writer, ValueTuple value, MessagePack.MessagePackSerializerOptions options) -> void MessagePack.ImmutableCollection.ImmutableArrayFormatter MessagePack.ImmutableCollection.ImmutableArrayFormatter.Deserialize(ref MessagePack.MessagePackReader reader, MessagePack.MessagePackSerializerOptions options) -> System.Collections.Immutable.ImmutableArray MessagePack.ImmutableCollection.ImmutableArrayFormatter.ImmutableArrayFormatter() -> void @@ -68,6 +74,8 @@ MessagePack.ImmutableCollection.InterfaceImmutableSetFormatter.InterfaceImmut MessagePack.ImmutableCollection.InterfaceImmutableStackFormatter MessagePack.ImmutableCollection.InterfaceImmutableStackFormatter.InterfaceImmutableStackFormatter() -> void MessagePack.Resolvers.ExpandoObjectResolver +MessagePack.Resolvers.TypelessInterfaceObjectResolver +MessagePack.Resolvers.TypelessInterfaceObjectResolver.GetFormatter() -> MessagePack.Formatters.IMessagePackFormatter override MessagePack.ImmutableCollection.ImmutableDictionaryFormatter.Add(System.Collections.Immutable.ImmutableDictionary.Builder collection, int index, TKey key, TValue value, MessagePack.MessagePackSerializerOptions options) -> void override MessagePack.ImmutableCollection.ImmutableDictionaryFormatter.Complete(System.Collections.Immutable.ImmutableDictionary.Builder intermediateCollection) -> System.Collections.Immutable.ImmutableDictionary override MessagePack.ImmutableCollection.ImmutableDictionaryFormatter.Create(int count, MessagePack.MessagePackSerializerOptions options) -> System.Collections.Immutable.ImmutableDictionary.Builder @@ -119,4 +127,5 @@ static readonly MessagePack.Formatters.TypeFormatter.Instance -> MessagePack. static readonly MessagePack.ImmutableCollection.ImmutableCollectionResolver.Instance -> MessagePack.ImmutableCollection.ImmutableCollectionResolver static readonly MessagePack.Resolvers.ExpandoObjectResolver.Instance -> MessagePack.IFormatterResolver static readonly MessagePack.Resolvers.ExpandoObjectResolver.Options -> MessagePack.MessagePackSerializerOptions +static readonly MessagePack.Resolvers.TypelessInterfaceObjectResolver.Instance -> MessagePack.IFormatterResolver virtual MessagePack.Formatters.PrimitiveObjectFormatter.DeserializeMap(ref MessagePack.MessagePackReader reader, int length, MessagePack.MessagePackSerializerOptions options) -> object From 1dbee1e254d4a32ba5c69f673c3bb63529d02eb1 Mon Sep 17 00:00:00 2001 From: neuecc Date: Fri, 9 Oct 2020 08:57:19 +0900 Subject: [PATCH 02/18] cleanup, remove typelessinterfaceobjectresolver --- .../Resolvers/DynamicObjectResolver.cs | 8 +++--- .../TypelessContractlessStandardResolver.cs | 1 - .../Resolvers/TypelessObjectResolver.cs | 28 ++++--------------- .../MessagePackSerializerTypelessTests.cs | 2 ++ src/MessagePack/PublicAPI.Unshipped.txt | 3 -- 5 files changed, 11 insertions(+), 31 deletions(-) diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/DynamicObjectResolver.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/DynamicObjectResolver.cs index 124f264bf..1628d0c36 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/DynamicObjectResolver.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/DynamicObjectResolver.cs @@ -69,7 +69,7 @@ static FormatterCache() { TypeInfo ti = typeof(T).GetTypeInfo(); - if (ti.IsInterface) + if (ti.IsInterface || ti.IsAbstract) { return; } @@ -129,7 +129,7 @@ static FormatterCache() { TypeInfo ti = typeof(T).GetTypeInfo(); - if (ti.IsInterface) + if (ti.IsInterface || ti.IsAbstract) { return; } @@ -205,7 +205,7 @@ static FormatterCache() TypeInfo ti = typeof(T).GetTypeInfo(); - if (ti.IsInterface) + if (ti.IsInterface || ti.IsAbstract) { return; } @@ -266,7 +266,7 @@ static FormatterCache() TypeInfo ti = typeof(T).GetTypeInfo(); - if (ti.IsInterface) + if (ti.IsInterface || ti.IsAbstract) { return; } diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/TypelessContractlessStandardResolver.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/TypelessContractlessStandardResolver.cs index 1b3d9c4fc..df789b9ef 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/TypelessContractlessStandardResolver.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/TypelessContractlessStandardResolver.cs @@ -41,7 +41,6 @@ public sealed class TypelessContractlessStandardResolver : IFormatterResolver DynamicUnionResolver.Instance, // Try Union(Interface) DynamicObjectResolver.Instance, // Try Object #endif - TypelessInterfaceObjectResolver.Instance, // can not serialize abstract/interface type on ContractlessResolver, hook before it. DynamicContractlessObjectResolverAllowPrivate.Instance, // Serializes keys as strings TypelessObjectResolver.Instance, }; diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/TypelessObjectResolver.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/TypelessObjectResolver.cs index 36b3fdf02..2dd37148b 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/TypelessObjectResolver.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/TypelessObjectResolver.cs @@ -35,6 +35,11 @@ private TypelessObjectResolver() /// public IMessagePackFormatter GetFormatter() { + if (typeof(T).IsAbstract || typeof(T).IsInterface) + { + return new ForceTypelessFormatter(); + } + if (typeof(T) == typeof(object)) { return (IMessagePackFormatter)TypelessFormatter.Instance; @@ -55,29 +60,6 @@ public IMessagePackFormatter GetFormatter() } } - /// - /// Helper resolver for interface/abstract type which not implements Union attribute. - /// - public sealed class TypelessInterfaceObjectResolver : IFormatterResolver - { - public static readonly IFormatterResolver Instance = new TypelessInterfaceObjectResolver(); - - private TypelessInterfaceObjectResolver() - { - } - - /// - public IMessagePackFormatter GetFormatter() - { - if (typeof(T).IsAbstract || typeof(T).IsInterface) - { - return new ForceTypelessFormatter(); - } - - return null; - } - } - /* helpers for TypelessFormatter */ internal sealed class ForceSizePrimitiveObjectResolver : IFormatterResolver diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTypelessTests.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTypelessTests.cs index 4364ef90f..872115496 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTypelessTests.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTypelessTests.cs @@ -78,6 +78,8 @@ public void OmitAssemblyVersion() [Fact] public void SerializeInterface() { + var foo = MessagePackSerializer.Typeless.DefaultOptions.Resolver.GetFormatter(); + var v = new Holder() { T1 = new TypelessInterface { X = 999 }, T2 = new TypelessNonAbstract { X = 19, Y = 9999 } }; var bin = MessagePackSerializer.Typeless.Serialize(v); var v2 = MessagePackSerializer.Typeless.Deserialize(bin).IsInstanceOf(); diff --git a/src/MessagePack/PublicAPI.Unshipped.txt b/src/MessagePack/PublicAPI.Unshipped.txt index c21a26704..17066bab4 100644 --- a/src/MessagePack/PublicAPI.Unshipped.txt +++ b/src/MessagePack/PublicAPI.Unshipped.txt @@ -74,8 +74,6 @@ MessagePack.ImmutableCollection.InterfaceImmutableSetFormatter.InterfaceImmut MessagePack.ImmutableCollection.InterfaceImmutableStackFormatter MessagePack.ImmutableCollection.InterfaceImmutableStackFormatter.InterfaceImmutableStackFormatter() -> void MessagePack.Resolvers.ExpandoObjectResolver -MessagePack.Resolvers.TypelessInterfaceObjectResolver -MessagePack.Resolvers.TypelessInterfaceObjectResolver.GetFormatter() -> MessagePack.Formatters.IMessagePackFormatter override MessagePack.ImmutableCollection.ImmutableDictionaryFormatter.Add(System.Collections.Immutable.ImmutableDictionary.Builder collection, int index, TKey key, TValue value, MessagePack.MessagePackSerializerOptions options) -> void override MessagePack.ImmutableCollection.ImmutableDictionaryFormatter.Complete(System.Collections.Immutable.ImmutableDictionary.Builder intermediateCollection) -> System.Collections.Immutable.ImmutableDictionary override MessagePack.ImmutableCollection.ImmutableDictionaryFormatter.Create(int count, MessagePack.MessagePackSerializerOptions options) -> System.Collections.Immutable.ImmutableDictionary.Builder @@ -127,5 +125,4 @@ static readonly MessagePack.Formatters.TypeFormatter.Instance -> MessagePack. static readonly MessagePack.ImmutableCollection.ImmutableCollectionResolver.Instance -> MessagePack.ImmutableCollection.ImmutableCollectionResolver static readonly MessagePack.Resolvers.ExpandoObjectResolver.Instance -> MessagePack.IFormatterResolver static readonly MessagePack.Resolvers.ExpandoObjectResolver.Options -> MessagePack.MessagePackSerializerOptions -static readonly MessagePack.Resolvers.TypelessInterfaceObjectResolver.Instance -> MessagePack.IFormatterResolver virtual MessagePack.Formatters.PrimitiveObjectFormatter.DeserializeMap(ref MessagePack.MessagePackReader reader, int length, MessagePack.MessagePackSerializerOptions options) -> object From 1522bb919aabb4a3025f8ed6005c442e9caea0c6 Mon Sep 17 00:00:00 2001 From: neuecc Date: Fri, 9 Oct 2020 09:20:25 +0900 Subject: [PATCH 03/18] fix unshipped --- src/MessagePack/PublicAPI.Unshipped.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/MessagePack/PublicAPI.Unshipped.txt b/src/MessagePack/PublicAPI.Unshipped.txt index 17066bab4..e07f74a8e 100644 --- a/src/MessagePack/PublicAPI.Unshipped.txt +++ b/src/MessagePack/PublicAPI.Unshipped.txt @@ -36,8 +36,6 @@ MessagePack.Formatters.ReadOnlySequenceFormatter.Serialize(ref MessagePack.Me MessagePack.Formatters.TypeFormatter MessagePack.Formatters.TypeFormatter.Deserialize(ref MessagePack.MessagePackReader reader, MessagePack.MessagePackSerializerOptions options) -> T MessagePack.Formatters.TypeFormatter.Serialize(ref MessagePack.MessagePackWriter writer, T value, MessagePack.MessagePackSerializerOptions options) -> void -MessagePack.Formatters.ValueTupleFormatter.Deserialize(ref MessagePack.MessagePackReader reader, MessagePack.MessagePackSerializerOptions options) -> ValueTuple -MessagePack.Formatters.ValueTupleFormatter.Serialize(ref MessagePack.MessagePackWriter writer, ValueTuple value, MessagePack.MessagePackSerializerOptions options) -> void MessagePack.ImmutableCollection.ImmutableArrayFormatter MessagePack.ImmutableCollection.ImmutableArrayFormatter.Deserialize(ref MessagePack.MessagePackReader reader, MessagePack.MessagePackSerializerOptions options) -> System.Collections.Immutable.ImmutableArray MessagePack.ImmutableCollection.ImmutableArrayFormatter.ImmutableArrayFormatter() -> void From dddacefb8ddff305129ac11bd9971419f2696c2c Mon Sep 17 00:00:00 2001 From: neuecc Date: Thu, 22 Oct 2020 17:44:24 +0900 Subject: [PATCH 04/18] inlined ExpandoObjectFormatter serialize --- .../MessagePack/Formatters/ExpandoObjectFormatter.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/ExpandoObjectFormatter.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/ExpandoObjectFormatter.cs index bad490b58..a0d9c6c05 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/ExpandoObjectFormatter.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/ExpandoObjectFormatter.cs @@ -51,8 +51,16 @@ public ExpandoObject Deserialize(ref MessagePackReader reader, MessagePackSerial public void Serialize(ref MessagePackWriter writer, ExpandoObject value, MessagePackSerializerOptions options) { - var dictionaryFormatter = options.Resolver.GetFormatterWithVerify>(); - dictionaryFormatter.Serialize(ref writer, value, options); + var dict = (IDictionary)value; + var keyFormatter = options.Resolver.GetFormatterWithVerify(); + var valueFormatter = options.Resolver.GetFormatterWithVerify(); + + writer.WriteMapHeader(dict.Count); + foreach (var item in dict) + { + keyFormatter.Serialize(ref writer, item.Key, options); + valueFormatter.Serialize(ref writer, item.Value, options); + } } } } From ccc02ab8293a76defb586f18ccf33a57ebd6e9e8 Mon Sep 17 00:00:00 2001 From: neuecc Date: Thu, 22 Oct 2020 17:44:59 +0900 Subject: [PATCH 05/18] use formatter cache for TypelessObjectResolver --- .../Resolvers/TypelessObjectResolver.cs | 38 +++++++++++-------- .../MessagePackSerializerTypelessTests.cs | 2 - 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/TypelessObjectResolver.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/TypelessObjectResolver.cs index 2dd37148b..3633f1c24 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/TypelessObjectResolver.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Resolvers/TypelessObjectResolver.cs @@ -35,27 +35,35 @@ private TypelessObjectResolver() /// public IMessagePackFormatter GetFormatter() { - if (typeof(T).IsAbstract || typeof(T).IsInterface) - { - return new ForceTypelessFormatter(); - } + return Cache.Formatter; + } - if (typeof(T) == typeof(object)) - { - return (IMessagePackFormatter)TypelessFormatter.Instance; - } - else + private static class Cache + { + public static readonly IMessagePackFormatter Formatter; + + static Cache() { - foreach (IFormatterResolver item in Resolvers) + if (typeof(T).IsAbstract || typeof(T).IsInterface) + { + Formatter = new ForceTypelessFormatter(); + } + + if (typeof(T) == typeof(object)) { - IMessagePackFormatter f = item.GetFormatter(); - if (f != null) + Formatter = (IMessagePackFormatter)TypelessFormatter.Instance; + } + else + { + foreach (var item in Resolvers) { - return f; + var f = item.GetFormatter(); + if (f != null) + { + Formatter = f; + } } } - - return null; } } } diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTypelessTests.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTypelessTests.cs index 872115496..4364ef90f 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTypelessTests.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTypelessTests.cs @@ -78,8 +78,6 @@ public void OmitAssemblyVersion() [Fact] public void SerializeInterface() { - var foo = MessagePackSerializer.Typeless.DefaultOptions.Resolver.GetFormatter(); - var v = new Holder() { T1 = new TypelessInterface { X = 999 }, T2 = new TypelessNonAbstract { X = 19, Y = 9999 } }; var bin = MessagePackSerializer.Typeless.Serialize(v); var v2 = MessagePackSerializer.Typeless.Deserialize(bin).IsInstanceOf(); From c00474df5b364b4129e536efdb085552be70b02b Mon Sep 17 00:00:00 2001 From: neuecc Date: Fri, 23 Oct 2020 17:34:53 +0900 Subject: [PATCH 06/18] NonGenerics Serialize/Deserialize uses reflection directly on Unity IL2CPP --- .../MessagePackSerializer.NonGeneric.cs | 56 +++++++++++++++---- .../ContractlessStandardResolverTest.cs | 6 ++ .../DynamicObjectResolverOrderTest.cs | 5 ++ .../ShareTests/DynamicObjectResolverTests.cs | 5 ++ .../Tests/ShareTests/ExpandoObjectTests.cs | 5 ++ .../ShareTests/MessagePackSecurityTests.cs | 6 ++ .../ShareTests/MessagePackSerializerTest.cs | 32 ++++++----- 7 files changed, 91 insertions(+), 24 deletions(-) diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSerializer.NonGeneric.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSerializer.NonGeneric.cs index bc467b69e..281e20f31 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSerializer.NonGeneric.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackSerializer.NonGeneric.cs @@ -127,7 +127,9 @@ internal CompiledMethods(Type type) { // public static byte[] Serialize(T obj, MessagePackSerializerOptions options, CancellationToken cancellationToken) MethodInfo serialize = GetMethod(nameof(Serialize), type, new Type[] { null, typeof(MessagePackSerializerOptions), typeof(CancellationToken) }); - +#if ENABLE_IL2CPP + this.Serialize_T_Options = (x, y, z) => (byte[])serialize.Invoke(null, new object[] { x, y, z }); +#else ParameterExpression param1 = Expression.Parameter(typeof(object), "obj"); ParameterExpression param2 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options"); ParameterExpression param3 = Expression.Parameter(typeof(CancellationToken), "cancellationToken"); @@ -141,12 +143,15 @@ internal CompiledMethods(Type type) Func lambda = Expression.Lambda>(body, param1, param2, param3).Compile(PreferInterpretation); this.Serialize_T_Options = lambda; +#endif } { // public static void Serialize(Stream stream, T obj, MessagePackSerializerOptions options, CancellationToken cancellationToken) MethodInfo serialize = GetMethod(nameof(Serialize), type, new Type[] { typeof(Stream), null, typeof(MessagePackSerializerOptions), typeof(CancellationToken) }); - +#if ENABLE_IL2CPP + this.Serialize_Stream_T_Options_CancellationToken = (x, y, z, a) => serialize.Invoke(null, new object[] { x, y, z, a }); +#else ParameterExpression param1 = Expression.Parameter(typeof(Stream), "stream"); ParameterExpression param2 = Expression.Parameter(typeof(object), "obj"); ParameterExpression param3 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options"); @@ -162,12 +167,15 @@ internal CompiledMethods(Type type) Action lambda = Expression.Lambda>(body, param1, param2, param3, param4).Compile(PreferInterpretation); this.Serialize_Stream_T_Options_CancellationToken = lambda; +#endif } { // public static Task SerializeAsync(Stream stream, T obj, MessagePackSerializerOptions options, CancellationToken cancellationToken) MethodInfo serialize = GetMethod(nameof(SerializeAsync), type, new Type[] { typeof(Stream), null, typeof(MessagePackSerializerOptions), typeof(CancellationToken) }); - +#if ENABLE_IL2CPP + this.SerializeAsync_Stream_T_Options_CancellationToken = (x, y, z, a) => (Task)serialize.Invoke(null, new object[] { x, y, z, a }); +#else ParameterExpression param1 = Expression.Parameter(typeof(Stream), "stream"); ParameterExpression param2 = Expression.Parameter(typeof(object), "obj"); ParameterExpression param3 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options"); @@ -183,12 +191,15 @@ internal CompiledMethods(Type type) Func lambda = Expression.Lambda>(body, param1, param2, param3, param4).Compile(PreferInterpretation); this.SerializeAsync_Stream_T_Options_CancellationToken = lambda; +#endif } { // public static Task Serialize(IBufferWriter writer, T obj, MessagePackSerializerOptions options, CancellationToken cancellationToken) MethodInfo serialize = GetMethod(nameof(Serialize), type, new Type[] { typeof(IBufferWriter), null, typeof(MessagePackSerializerOptions), typeof(CancellationToken) }); - +#if ENABLE_IL2CPP + this.Serialize_IBufferWriter_T_Options_CancellationToken = (x, y, z, a) => serialize.Invoke(null, new object[] { x, y, z, a }); +#else ParameterExpression param1 = Expression.Parameter(typeof(IBufferWriter), "writer"); ParameterExpression param2 = Expression.Parameter(typeof(object), "obj"); ParameterExpression param3 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options"); @@ -204,12 +215,15 @@ internal CompiledMethods(Type type) Action, object, MessagePackSerializerOptions, CancellationToken> lambda = Expression.Lambda, object, MessagePackSerializerOptions, CancellationToken>>(body, param1, param2, param3, param4).Compile(PreferInterpretation); this.Serialize_IBufferWriter_T_Options_CancellationToken = lambda; +#endif } { // public static void Serialize(ref MessagePackWriter writer, T obj, MessagePackSerializerOptions options) MethodInfo serialize = GetMethod(nameof(Serialize), type, new Type[] { typeof(MessagePackWriter).MakeByRefType(), null, typeof(MessagePackSerializerOptions) }); - +#if ENABLE_IL2CPP + this.Serialize_MessagePackWriter_T_Options = (ref MessagePackWriter x, object y, MessagePackSerializerOptions z) => ThrowRefStructNotSupported(); +#else ParameterExpression param1 = Expression.Parameter(typeof(MessagePackWriter).MakeByRefType(), "writer"); ParameterExpression param2 = Expression.Parameter(typeof(object), "obj"); ParameterExpression param3 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options"); @@ -223,24 +237,30 @@ internal CompiledMethods(Type type) MessagePackWriterSerialize lambda = Expression.Lambda(body, param1, param2, param3).Compile(PreferInterpretation); this.Serialize_MessagePackWriter_T_Options = lambda; +#endif } { // public static T Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) MethodInfo deserialize = GetMethod(nameof(Deserialize), type, new Type[] { typeof(MessagePackReader).MakeByRefType(), typeof(MessagePackSerializerOptions) }); - +#if ENABLE_IL2CPP + this.Deserialize_MessagePackReader_Options = (ref MessagePackReader reader, MessagePackSerializerOptions options) => { ThrowRefStructNotSupported(); return null; }; +#else ParameterExpression param1 = Expression.Parameter(typeof(MessagePackReader).MakeByRefType(), "reader"); ParameterExpression param2 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options"); UnaryExpression body = Expression.Convert(Expression.Call(null, deserialize, param1, param2), typeof(object)); MessagePackReaderDeserialize lambda = Expression.Lambda(body, param1, param2).Compile(); this.Deserialize_MessagePackReader_Options = lambda; +#endif } { // public static T Deserialize(Stream stream, MessagePackSerializerOptions options, CancellationToken cancellationToken) MethodInfo deserialize = GetMethod(nameof(Deserialize), type, new Type[] { typeof(Stream), typeof(MessagePackSerializerOptions), typeof(CancellationToken) }); - +#if ENABLE_IL2CPP + this.Deserialize_Stream_Options_CancellationToken = (x, y, z) => deserialize.Invoke(null, new object[] { x, y, z }); +#else ParameterExpression param1 = Expression.Parameter(typeof(Stream), "stream"); ParameterExpression param2 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options"); ParameterExpression param3 = Expression.Parameter(typeof(CancellationToken), "cancellationToken"); @@ -248,12 +268,15 @@ internal CompiledMethods(Type type) Func lambda = Expression.Lambda>(body, param1, param2, param3).Compile(PreferInterpretation); this.Deserialize_Stream_Options_CancellationToken = lambda; +#endif } { // public static ValueTask DeserializeObjectAsync(Stream stream, MessagePackSerializerOptions options, CancellationToken cancellationToken) MethodInfo deserialize = GetMethod(nameof(DeserializeObjectAsync), type, new Type[] { typeof(Stream), typeof(MessagePackSerializerOptions), typeof(CancellationToken) }); - +#if ENABLE_IL2CPP + this.DeserializeAsync_Stream_Options_CancellationToken = (x, y, z) => (ValueTask)deserialize.Invoke(null, new object[] { x, y, z }); +#else ParameterExpression param1 = Expression.Parameter(typeof(Stream), "stream"); ParameterExpression param2 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options"); ParameterExpression param3 = Expression.Parameter(typeof(CancellationToken), "cancellationToken"); @@ -261,12 +284,15 @@ internal CompiledMethods(Type type) Func> lambda = Expression.Lambda>>(body, param1, param2, param3).Compile(PreferInterpretation); this.DeserializeAsync_Stream_Options_CancellationToken = lambda; +#endif } { // public static T Deserialize(ReadOnlyMemory bytes, MessagePackSerializerOptions options, CancellationToken cancellationToken) MethodInfo deserialize = GetMethod(nameof(Deserialize), type, new Type[] { typeof(ReadOnlyMemory), typeof(MessagePackSerializerOptions), typeof(CancellationToken) }); - +#if ENABLE_IL2CPP + this.Deserialize_ReadOnlyMemory_Options = (x, y, z) => deserialize.Invoke(null, new object[] { x, y, z }); +#else ParameterExpression param1 = Expression.Parameter(typeof(ReadOnlyMemory), "bytes"); ParameterExpression param2 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options"); ParameterExpression param3 = Expression.Parameter(typeof(CancellationToken), "cancellationToken"); @@ -274,12 +300,15 @@ internal CompiledMethods(Type type) Func, MessagePackSerializerOptions, CancellationToken, object> lambda = Expression.Lambda, MessagePackSerializerOptions, CancellationToken, object>>(body, param1, param2, param3).Compile(PreferInterpretation); this.Deserialize_ReadOnlyMemory_Options = lambda; +#endif } { // public static T Deserialize(ReadOnlySequence bytes, MessagePackSerializerOptions options, CancellationToken cancellationToken) MethodInfo deserialize = GetMethod(nameof(Deserialize), type, new Type[] { typeof(ReadOnlySequence).MakeByRefType(), typeof(MessagePackSerializerOptions), typeof(CancellationToken) }); - +#if ENABLE_IL2CPP + this.Deserialize_ReadOnlySequence_Options_CancellationToken = (x, y, z) => deserialize.Invoke(null, new object[] { x, y, z }); +#else ParameterExpression param1 = Expression.Parameter(typeof(ReadOnlySequence), "bytes"); ParameterExpression param2 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options"); ParameterExpression param3 = Expression.Parameter(typeof(CancellationToken), "cancellationToken"); @@ -287,9 +316,16 @@ internal CompiledMethods(Type type) Func, MessagePackSerializerOptions, CancellationToken, object> lambda = Expression.Lambda, MessagePackSerializerOptions, CancellationToken, object>>(body, param1, param2, param3).Compile(PreferInterpretation); this.Deserialize_ReadOnlySequence_Options_CancellationToken = lambda; +#endif } } + private static void ThrowRefStructNotSupported() + { + // C# 8.0 is not supported call `ref struct` via reflection. (It is milestoned at .NET 6) + throw new NotSupportedException("MessagePackWriter/Reader overload is not supported in MessagePackSerializer.NonGenerics."); + } + // null is generic type marker. private static MethodInfo GetMethod(string methodName, Type type, Type[] parameters) { diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ContractlessStandardResolverTest.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ContractlessStandardResolverTest.cs index 5fd8c31de..51769b8f6 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ContractlessStandardResolverTest.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ContractlessStandardResolverTest.cs @@ -16,6 +16,12 @@ public class ContractlessStandardResolverTest { private readonly ITestOutputHelper logger; + + public ContractlessStandardResolverTest() + { + this.logger = new NullTestOutputHelper(); + } + public ContractlessStandardResolverTest(ITestOutputHelper logger) { this.logger = logger; diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/DynamicObjectResolverOrderTest.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/DynamicObjectResolverOrderTest.cs index 50108b5f8..3e147728c 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/DynamicObjectResolverOrderTest.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/DynamicObjectResolverOrderTest.cs @@ -17,6 +17,11 @@ public class DynamicObjectResolverOrderTest { private readonly ITestOutputHelper logger; + public DynamicObjectResolverOrderTest() + { + this.logger = new NullTestOutputHelper(); + } + public DynamicObjectResolverOrderTest(ITestOutputHelper logger) { this.logger = logger; diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/DynamicObjectResolverTests.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/DynamicObjectResolverTests.cs index 7366440a2..10549388f 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/DynamicObjectResolverTests.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/DynamicObjectResolverTests.cs @@ -15,6 +15,11 @@ public class DynamicObjectResolverTests { private readonly ITestOutputHelper logger; + public DynamicObjectResolverTests() + { + this.logger = new NullTestOutputHelper(); + } + public DynamicObjectResolverTests(ITestOutputHelper logger) { this.logger = logger; diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ExpandoObjectTests.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ExpandoObjectTests.cs index 16cfde599..932df9593 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ExpandoObjectTests.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ExpandoObjectTests.cs @@ -13,6 +13,11 @@ public class ExpandoObjectTests { private readonly ITestOutputHelper logger; + public ExpandoObjectTests() + { + this.logger = new NullTestOutputHelper(); + } + public ExpandoObjectTests(ITestOutputHelper logger) { this.logger = logger; diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSecurityTests.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSecurityTests.cs index dcc7a40ea..45c66394d 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSecurityTests.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSecurityTests.cs @@ -10,6 +10,11 @@ public class MessagePackSecurityTests { + public MessagePackSecurityTests() + { + Logger = new NullTestOutputHelper(); + } + public MessagePackSecurityTests(ITestOutputHelper logger) { Logger = logger; @@ -231,3 +236,4 @@ public enum SomeUInt64Enum : ulong { } } + diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTest.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTest.cs index eb7e1ca3c..fc302910d 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTest.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTest.cs @@ -21,8 +21,6 @@ namespace MessagePack.Tests { public class MessagePackSerializerTest { -#if !ENABLE_IL2CPP - [Fact] public void NonGeneric() { @@ -33,21 +31,25 @@ public void NonGeneric() var writer = new MessagePackWriter(writerBytes); var data1 = MessagePackSerializer.Deserialize(t, MessagePackSerializer.Serialize(t, data)) as FirstSimpleData; - var data2 = MessagePackSerializer.Deserialize(t, MessagePackSerializer.Serialize(t, data, StandardResolver.Options)) as FirstSimpleData; + var data2 = MessagePackSerializer.Deserialize(t, MessagePackSerializer.Serialize(t, data, MessagePackSerializer.DefaultOptions)) as FirstSimpleData; MessagePackSerializer.Serialize(t, ms, data); ms.Position = 0; var data3 = MessagePackSerializer.Deserialize(t, ms) as FirstSimpleData; ms = new MemoryStream(); - MessagePackSerializer.Serialize(t, ms, data, StandardResolver.Options); + MessagePackSerializer.Serialize(t, ms, data, MessagePackSerializer.DefaultOptions); ms.Position = 0; - var data4 = MessagePackSerializer.Deserialize(t, ms, StandardResolver.Options) as FirstSimpleData; + var data4 = MessagePackSerializer.Deserialize(t, ms, MessagePackSerializer.DefaultOptions) as FirstSimpleData; - MessagePackSerializer.Serialize(t, ref writer, data, StandardResolver.Options); +#if ENABLE_IL2CPP + var data5 = data4; +#else + MessagePackSerializer.Serialize(t, ref writer, data, MessagePackSerializer.DefaultOptions); writer.Flush(); var reader = new MessagePackReader(writerBytes.AsReadOnlySequence); - var data5 = MessagePackSerializer.Deserialize(t, ref reader, StandardResolver.Options) as FirstSimpleData; + var data5 = MessagePackSerializer.Deserialize(t, ref reader, MessagePackSerializer.DefaultOptions) as FirstSimpleData; +#endif new[] { data1.Prop1, data2.Prop1, data3.Prop1, data4.Prop1, data5.Prop1 }.Distinct().Is(data.Prop1); new[] { data1.Prop2, data2.Prop2, data3.Prop2, data4.Prop2, data5.Prop2 }.Distinct().Is(data.Prop2); @@ -63,27 +65,25 @@ public void NonGeneric_BufferWriter_ReadOnlySequence() var writerBytes = new Sequence(); var data1 = MessagePackSerializer.Deserialize(t, MessagePackSerializer.Serialize(t, data)) as FirstSimpleData; - var data2 = MessagePackSerializer.Deserialize(t, MessagePackSerializer.Serialize(t, data, StandardResolver.Options)) as FirstSimpleData; + var data2 = MessagePackSerializer.Deserialize(t, MessagePackSerializer.Serialize(t, data, MessagePackSerializer.DefaultOptions)) as FirstSimpleData; MessagePackSerializer.Serialize(t, ms, data); ms.Position = 0; var data3 = MessagePackSerializer.Deserialize(t, ms) as FirstSimpleData; ms = new MemoryStream(); - MessagePackSerializer.Serialize(t, ms, data, StandardResolver.Options); + MessagePackSerializer.Serialize(t, ms, data, MessagePackSerializer.DefaultOptions); ms.Position = 0; - var data4 = MessagePackSerializer.Deserialize(t, ms, StandardResolver.Options) as FirstSimpleData; + var data4 = MessagePackSerializer.Deserialize(t, ms, MessagePackSerializer.DefaultOptions) as FirstSimpleData; - MessagePackSerializer.Serialize(t, writerBytes, data, StandardResolver.Options); - var data5 = MessagePackSerializer.Deserialize(t, writerBytes.AsReadOnlySequence, StandardResolver.Options) as FirstSimpleData; + MessagePackSerializer.Serialize(t, writerBytes, data, MessagePackSerializer.DefaultOptions); + var data5 = MessagePackSerializer.Deserialize(t, writerBytes.AsReadOnlySequence, MessagePackSerializer.DefaultOptions) as FirstSimpleData; new[] { data1.Prop1, data2.Prop1, data3.Prop1, data4.Prop1, data5.Prop1 }.Distinct().Is(data.Prop1); new[] { data1.Prop2, data2.Prop2, data3.Prop2, data4.Prop2, data5.Prop2 }.Distinct().Is(data.Prop2); new[] { data1.Prop3, data2.Prop3, data3.Prop3, data4.Prop3, data5.Prop3 }.Distinct().Is(data.Prop3); } -#endif - #if !UNITY_2018_3_OR_NEWER /* Unity's NUnit currently no supported Task test. */ @@ -241,6 +241,8 @@ public void StackDepthCheck_Maps(bool convertToJson) } } +#if !ENABLE_IL2CPP + [Fact] public void StackDepthCheck_DynamicObjectResolver() { @@ -269,6 +271,8 @@ public void StackDepthCheck_DynamicObjectResolver() Assert.IsType(ex.InnerException); } +#endif + private delegate void WriterHelper(ref MessagePackWriter writer); private static (ReadOnlySequence Sequence, MessagePackSerializerOptions Options) StackDepthCheck_Helper(WriterHelper recursiveWriteOperation) From 1d77bc99b1a116bf56ad4e9bbbe4282864dbe3aa Mon Sep 17 00:00:00 2001 From: neuecc Date: Sat, 24 Oct 2020 10:36:07 +0900 Subject: [PATCH 07/18] NullTestOutputHelper --- .../ShareTests/ContractlessStandardResolverTest.cs | 1 - .../Tests/ShareTests/MessagePackSecurityTests.cs | 1 + .../Assets/Scripts/Tests/ShareTests/TestUtilities.cs | 12 ++++++++++++ .../Assets/Scripts/Tests/Shims/XUnit.cs | 11 ----------- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ContractlessStandardResolverTest.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ContractlessStandardResolverTest.cs index 51769b8f6..986871d0e 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ContractlessStandardResolverTest.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ContractlessStandardResolverTest.cs @@ -16,7 +16,6 @@ public class ContractlessStandardResolverTest { private readonly ITestOutputHelper logger; - public ContractlessStandardResolverTest() { this.logger = new NullTestOutputHelper(); diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSecurityTests.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSecurityTests.cs index 45c66394d..95a304661 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSecurityTests.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSecurityTests.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Runtime.Serialization; using MessagePack; +using MessagePack.Tests; using Xunit; using Xunit.Abstractions; diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/TestUtilities.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/TestUtilities.cs index ca099d773..0a4bf9fbf 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/TestUtilities.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/TestUtilities.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Text; using System.Threading; +using Xunit.Abstractions; namespace MessagePack.Tests { @@ -15,4 +16,15 @@ internal static class TestUtilities /// internal static bool IsRunningOnMono => Type.GetType("Mono.Runtime") != null; } + + public class NullTestOutputHelper : ITestOutputHelper + { + public void WriteLine(string message) + { + } + + public void WriteLine(string format, params object[] args) + { + } + } } diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/Shims/XUnit.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/Shims/XUnit.cs index bf02f5286..86efef462 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/Shims/XUnit.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/Shims/XUnit.cs @@ -144,15 +144,4 @@ public interface ITestOutputHelper void WriteLine(String message); void WriteLine(String format, params Object[] args); } - - public class NullTestOutputHelper : ITestOutputHelper - { - public void WriteLine(string message) - { - } - - public void WriteLine(string format, params object[] args) - { - } - } } From d372c7a9d32d2fbec871232b143ab666e53ee555 Mon Sep 17 00:00:00 2001 From: pCYSl5EDgo Date: Sat, 24 Oct 2020 13:57:47 +0900 Subject: [PATCH 08/18] Add descriptions about MessagePack.Experimental. --- README.md | 11 +++++++ src/MessagePack.Experimental/Experimental.md | 11 +++++++ .../HardwareIntrinsics/HardwareIntrinsics.md | 24 +++++++++++++++ .../UnsafeUnmanagedStructFormatter.md | 29 +++++++++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 src/MessagePack.Experimental/Experimental.md create mode 100644 src/MessagePack.Experimental/HardwareIntrinsics/HardwareIntrinsics.md create mode 100644 src/MessagePack.Experimental/UnsafeUnmanagedStructFormatter/UnsafeUnmanagedStructFormatter.md diff --git a/README.md b/README.md index c8cf1f2de..8751d4c7f 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ MessagePack has a compact binary size and a full set of general purpose expressi - [Be careful when copying buffers](#be-careful-when-copying-buffers) - [Choosing compression](#choosing-compression) - [Extensions](#extensions) +- [Experimental Features](#experimental-features) - [High-Level API (`MessagePackSerializer`)](#high-level-api-messagepackserializer) - [Multiple MessagePack structures on a single `Stream`](#multiple-messagepack-structures-on-a-single-stream) - [Low-Level API (`IMessagePackFormatter`)](#low-level-api-imessagepackformattert) @@ -983,6 +984,16 @@ You can make your own extension serializers or integrate with frameworks. Let's * [WebApiContrib.Core.Formatter.MessagePack](https://github.com/WebApiContrib/WebAPIContrib.Core#formatters) - supports ASP.NET Core MVC ([details in blog post](https://www.strathweb.com/2017/06/using-messagepack-with-asp-net-core-mvc/)) * [MessagePack.MediaTypeFormatter](https://github.com/sketch7/MessagePack.MediaTypeFormatter) - MessagePack MediaTypeFormatter +## Experimental Features + +MessagePack for C# has experimental features which provides you with very performant formatters. There is an official package. + +```ps1 +Install-Package MessagePack.Experimental +``` + +For detailed information, see: [Experimental.md](src/MessagePack.Experimental/Experimental.md) + # API ## High-Level API (`MessagePackSerializer`) diff --git a/src/MessagePack.Experimental/Experimental.md b/src/MessagePack.Experimental/Experimental.md new file mode 100644 index 000000000..50eee6876 --- /dev/null +++ b/src/MessagePack.Experimental/Experimental.md @@ -0,0 +1,11 @@ +# MessagePack.Experimental + +This C# project is the experimental project for the features which are very complex, unstable or unsafe. + +- [HardwareIntrinsics](HardwareIntrinsics/HardwareIntrinsics.md) +- [UnsafeUnmanagedStructFormatter](UnsafeUnmanagedStructFormatter/UnsafeUnmanagedStructFormatter.md) + +**Caution!** + +`MessagePack.Experimental` only targets `.NET Core 3.1` and above. +You can not use this in Unity and .NET Framework. \ No newline at end of file diff --git a/src/MessagePack.Experimental/HardwareIntrinsics/HardwareIntrinsics.md b/src/MessagePack.Experimental/HardwareIntrinsics/HardwareIntrinsics.md new file mode 100644 index 000000000..b67948f5c --- /dev/null +++ b/src/MessagePack.Experimental/HardwareIntrinsics/HardwareIntrinsics.md @@ -0,0 +1,24 @@ +# Abstract + +`Hardware Intrinsics` is a feature in order to utilize maximum power of the cpu. +You can serialize/deserialize primitive type array much faster than current implementation! + +Supported types + +- `sbyte[]` +- `short[]` +- `int[]` +- `bool[]` +- `float[]` +- `double[]` + +# Usage + +```csharp +var resolver = MessagePack.Resolvers.CompositeResolver.Create(new[] { PrimitiveArrayResolver.Instance, MessagePack.Resolvers.StandardResolver.Instance }); +``` + +# When will this feature become official? + +- The MessagePack-CSharp's lowest target framework is greater or equals to `.NET Core 3.1`. +- The current very complex and hard to understand implementation is rewritten. \ No newline at end of file diff --git a/src/MessagePack.Experimental/UnsafeUnmanagedStructFormatter/UnsafeUnmanagedStructFormatter.md b/src/MessagePack.Experimental/UnsafeUnmanagedStructFormatter/UnsafeUnmanagedStructFormatter.md new file mode 100644 index 000000000..a0f22ae71 --- /dev/null +++ b/src/MessagePack.Experimental/UnsafeUnmanagedStructFormatter/UnsafeUnmanagedStructFormatter.md @@ -0,0 +1,29 @@ +# Abstract + +`UnsafeUnmanagedStructFormatter`s (de)serialize the blittable value(s) directly. +They are very performant but unstable against the endian. + +You should be careful not to share the encoded byte[] among the different endian environments. + +Supported types (T where T : unamanaged) + +- `T` → `UnsafeUnmanagedStructFormatter` +- `T[]` → `UnsafeUnmanagedStructArrayFormatter` +- `Memory` → `UnsafeUnmanagedStructMemoryFormatter` +- `ReadOnlyMemory` → `UnsafeUnmanagedStructReadOnlyMemoryFormatter` +- `ReadOnlySequence` → `UnsafeUnmanagedStructReadOnlySequenceFormatter` + +# Usage + +```csharp +var resolver = MessagePack.Resolvers.CompositeResolver.Create( + new[] { new UnsafeUnmanagedStructFormatter(typeCode: 96) }, + new[] { MessagePack.Resolvers.StandardResolver.Instance }); +``` + +The constructor takes 1 sbyte value. +The sbyte value is the extension type code embedded in serialized byte sequence. + +# When will this feature become official? + +- Requests are needed. \ No newline at end of file From 488f59ae5d28b41fee50988135ce7ba45e4452c5 Mon Sep 17 00:00:00 2001 From: neuecc Date: Mon, 26 Oct 2020 16:02:09 +0900 Subject: [PATCH 09/18] fix for xUnit --- .../Tests/ShareTests/ContractlessStandardResolverTest.cs | 4 ++++ .../Tests/ShareTests/DynamicObjectResolverOrderTest.cs | 4 ++++ .../Scripts/Tests/ShareTests/DynamicObjectResolverTests.cs | 4 ++++ .../Assets/Scripts/Tests/ShareTests/ExpandoObjectTests.cs | 4 ++++ .../Scripts/Tests/ShareTests/MessagePackSecurityTests.cs | 4 ++++ 5 files changed, 20 insertions(+) diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ContractlessStandardResolverTest.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ContractlessStandardResolverTest.cs index 986871d0e..d05204268 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ContractlessStandardResolverTest.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ContractlessStandardResolverTest.cs @@ -16,11 +16,15 @@ public class ContractlessStandardResolverTest { private readonly ITestOutputHelper logger; +#if UNITY_2018_3_OR_NEWER + public ContractlessStandardResolverTest() { this.logger = new NullTestOutputHelper(); } +#endif + public ContractlessStandardResolverTest(ITestOutputHelper logger) { this.logger = logger; diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/DynamicObjectResolverOrderTest.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/DynamicObjectResolverOrderTest.cs index 3e147728c..9d08d789f 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/DynamicObjectResolverOrderTest.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/DynamicObjectResolverOrderTest.cs @@ -17,11 +17,15 @@ public class DynamicObjectResolverOrderTest { private readonly ITestOutputHelper logger; +#if UNITY_2018_3_OR_NEWER + public DynamicObjectResolverOrderTest() { this.logger = new NullTestOutputHelper(); } +#endif + public DynamicObjectResolverOrderTest(ITestOutputHelper logger) { this.logger = logger; diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/DynamicObjectResolverTests.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/DynamicObjectResolverTests.cs index 10549388f..38c80fe79 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/DynamicObjectResolverTests.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/DynamicObjectResolverTests.cs @@ -15,11 +15,15 @@ public class DynamicObjectResolverTests { private readonly ITestOutputHelper logger; +#if UNITY_2018_3_OR_NEWER + public DynamicObjectResolverTests() { this.logger = new NullTestOutputHelper(); } +#endif + public DynamicObjectResolverTests(ITestOutputHelper logger) { this.logger = logger; diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ExpandoObjectTests.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ExpandoObjectTests.cs index 932df9593..45b17edeb 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ExpandoObjectTests.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/ExpandoObjectTests.cs @@ -13,11 +13,15 @@ public class ExpandoObjectTests { private readonly ITestOutputHelper logger; +#if UNITY_2018_3_OR_NEWER + public ExpandoObjectTests() { this.logger = new NullTestOutputHelper(); } +#endif + public ExpandoObjectTests(ITestOutputHelper logger) { this.logger = logger; diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSecurityTests.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSecurityTests.cs index 95a304661..214634b07 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSecurityTests.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSecurityTests.cs @@ -11,11 +11,15 @@ public class MessagePackSecurityTests { +#if UNITY_2018_3_OR_NEWER + public MessagePackSecurityTests() { Logger = new NullTestOutputHelper(); } +#endif + public MessagePackSecurityTests(ITestOutputHelper logger) { Logger = logger; From 8dc688ed33f1285a6029f1b2099d4a445d49f0c1 Mon Sep 17 00:00:00 2001 From: neuecc Date: Mon, 26 Oct 2020 16:35:43 +0900 Subject: [PATCH 10/18] fix for fucking lint --- .../Assets/Scripts/Tests/ShareTests/MessagePackSecurityTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSecurityTests.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSecurityTests.cs index 214634b07..d89411e74 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSecurityTests.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSecurityTests.cs @@ -241,4 +241,3 @@ public enum SomeUInt64Enum : ulong { } } - From 66f3766b03e10d6d3e17dc5a83650d1b94b904cf Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 28 Oct 2020 09:31:26 -0600 Subject: [PATCH 11/18] Add xml doc comments to `CodeGenHelpers` --- .../MessagePack/Internal/CodeGenHelpers.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/CodeGenHelpers.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/CodeGenHelpers.cs index 67880968b..b08a5ac76 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/CodeGenHelpers.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Internal/CodeGenHelpers.cs @@ -17,6 +17,11 @@ namespace MessagePack.Internal [EditorBrowsable(EditorBrowsableState.Never)] public static class CodeGenHelpers { + /// + /// Gets the messagepack encoding for a given string. + /// + /// The string to encode. + /// The messagepack encoding for , including messagepack header and UTF-8 bytes. public static byte[] GetEncodedStringBytes(string value) { var byteCount = StringEncoding.UTF8.GetByteCount(value); @@ -57,6 +62,12 @@ public static byte[] GetEncodedStringBytes(string value) } } + /// + /// Gets a single containing all bytes in a given . + /// An array may be allocated if the bytes are not already contiguous in memory. + /// + /// The sequence to get a span for. + /// The span. public static ReadOnlySpan GetSpanFromSequence(in ReadOnlySequence sequence) { if (sequence.IsSingleSegment) @@ -67,6 +78,12 @@ public static ReadOnlySpan GetSpanFromSequence(in ReadOnlySequence s return sequence.ToArray(); } + /// + /// Reads a string as a contiguous span of UTF-8 encoded characters. + /// An array may be allocated if the string is not already contiguous in memory. + /// + /// The reader to use. + /// The span of UTF-8 encoded characters. public static ReadOnlySpan ReadStringSpan(ref MessagePackReader reader) { if (!reader.TryReadStringSpan(out ReadOnlySpan result)) @@ -77,6 +94,11 @@ public static ReadOnlySpan ReadStringSpan(ref MessagePackReader reader) return result; } + /// + /// Creates a array for a given sequence, or if the optional sequence is itself . + /// + /// The sequence. + /// The byte array or . public static byte[] GetArrayFromNullableSequence(in ReadOnlySequence? sequence) => sequence?.ToArray(); private static ReadOnlySpan GetSpanFromSequence(in ReadOnlySequence? sequence) From 8ca6729f7520b3f7ae1ec4769eff28a2e301ac31 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 30 Oct 2020 14:48:55 -0600 Subject: [PATCH 12/18] Fix mpc arg documentation We do not support a comma-delimited list. Supporting it wouldn't be significantly more efficient than having the caller invoke the tool multiple times, so I'm fixing the docs to reflect functionality rather than adding list support. --- src/MessagePack.Generator/MessagepackCompiler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MessagePack.Generator/MessagepackCompiler.cs b/src/MessagePack.Generator/MessagepackCompiler.cs index fd5ba0ced..dfea81961 100644 --- a/src/MessagePack.Generator/MessagepackCompiler.cs +++ b/src/MessagePack.Generator/MessagepackCompiler.cs @@ -39,7 +39,7 @@ await Host.CreateDefaultBuilder() } public async Task RunAsync( - [Option("i", "Input path of analyze MSBuild project file or directory, if input multiple project files split with ','.")] string input, + [Option("i", "Input path to MSBuild project file or the directory containing Unity source files.")] string input, [Option("o", "Output file path(.cs) or directory (multiple generate file).")] string output, [Option("c", "Conditional compiler symbols, split with ','. Ignored if a project file is specified for input.")] string? conditionalSymbol = null, [Option("r", "Set resolver name.")] string resolverName = "GeneratedResolver", From dedb9c361ebadfd87b1c3492a56b8c03634aae98 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 30 Oct 2020 15:04:51 -0600 Subject: [PATCH 13/18] Fix `[MessagePackFormatter(TypelessFormatter)]` This corrects a regression from 1.x to 2.0. Fixes #1097 --- .../Formatters/TypelessFormatter.cs | 38 +++++++++---------- .../MessagePackSerializerTypelessTests.cs | 17 +++++++++ src/MessagePack/PublicAPI.Unshipped.txt | 1 + 3 files changed, 37 insertions(+), 19 deletions(-) diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/TypelessFormatter.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/TypelessFormatter.cs index 5c9c97c77..0d158a355 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/TypelessFormatter.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/TypelessFormatter.cs @@ -50,11 +50,11 @@ public sealed class TypelessFormatter : IMessagePackFormatter /// public static readonly IMessagePackFormatter Instance = new TypelessFormatter(); - private readonly ThreadsafeTypeKeyHashTable serializers = new ThreadsafeTypeKeyHashTable(); - private readonly ThreadsafeTypeKeyHashTable deserializers = new ThreadsafeTypeKeyHashTable(); - private readonly ThreadsafeTypeKeyHashTable fullTypeNameCache = new ThreadsafeTypeKeyHashTable(); - private readonly ThreadsafeTypeKeyHashTable shortenedTypeNameCache = new ThreadsafeTypeKeyHashTable(); - private readonly AsymmetricKeyHashTable, Type> typeCache = new AsymmetricKeyHashTable, Type>(new StringArraySegmentByteAscymmetricEqualityComparer()); + private static readonly ThreadsafeTypeKeyHashTable Serializers = new ThreadsafeTypeKeyHashTable(); + private static readonly ThreadsafeTypeKeyHashTable Deserializers = new ThreadsafeTypeKeyHashTable(); + private static readonly ThreadsafeTypeKeyHashTable FullTypeNameCache = new ThreadsafeTypeKeyHashTable(); + private static readonly ThreadsafeTypeKeyHashTable ShortenedTypeNameCache = new ThreadsafeTypeKeyHashTable(); + private static readonly AsymmetricKeyHashTable, Type> TypeCache = new AsymmetricKeyHashTable, Type>(new StringArraySegmentByteAscymmetricEqualityComparer()); private static readonly HashSet UseBuiltinTypes = new HashSet { @@ -107,10 +107,10 @@ public sealed class TypelessFormatter : IMessagePackFormatter // mscorlib or System.Private.CoreLib private static readonly bool IsMscorlib = typeof(int).AssemblyQualifiedName.Contains("mscorlib"); - private TypelessFormatter() + static TypelessFormatter() { - this.serializers.TryAdd(typeof(object), _ => (object p1, ref MessagePackWriter p2, object p3, MessagePackSerializerOptions p4) => { }); - this.deserializers.TryAdd(typeof(object), _ => (object p1, ref MessagePackReader p2, MessagePackSerializerOptions p3) => new object()); + Serializers.TryAdd(typeof(object), _ => (object p1, ref MessagePackWriter p2, object p3, MessagePackSerializerOptions p4) => { }); + Deserializers.TryAdd(typeof(object), _ => (object p1, ref MessagePackReader p2, MessagePackSerializerOptions p3) => new object()); } private string BuildTypeName(Type type, MessagePackSerializerOptions options) @@ -145,7 +145,7 @@ public void Serialize(ref MessagePackWriter writer, object value, MessagePackSer Type type = value.GetType(); byte[] typeName; - var typeNameCache = options.OmitAssemblyVersion ? this.shortenedTypeNameCache : this.fullTypeNameCache; + var typeNameCache = options.OmitAssemblyVersion ? ShortenedTypeNameCache : FullTypeNameCache; if (!typeNameCache.TryGetValue(type, out typeName)) { TypeInfo ti = type.GetTypeInfo(); @@ -170,12 +170,12 @@ public void Serialize(ref MessagePackWriter writer, object value, MessagePackSer var formatter = options.Resolver.GetFormatterDynamicWithVerify(type); // don't use GetOrAdd for avoid closure capture. - if (!this.serializers.TryGetValue(type, out SerializeMethod serializeMethod)) + if (!Serializers.TryGetValue(type, out SerializeMethod serializeMethod)) { // double check locking... - lock (this.serializers) + lock (Serializers) { - if (!this.serializers.TryGetValue(type, out serializeMethod)) + if (!Serializers.TryGetValue(type, out serializeMethod)) { TypeInfo ti = type.GetTypeInfo(); @@ -196,7 +196,7 @@ public void Serialize(ref MessagePackWriter writer, object value, MessagePackSer serializeMethod = Expression.Lambda(body, param0, param1, param2, param3).Compile(); - this.serializers.TryAdd(type, serializeMethod); + Serializers.TryAdd(type, serializeMethod); } } } @@ -263,7 +263,7 @@ private object DeserializeByTypeName(ArraySegment typeName, ref MessagePac { // try get type with assembly name, throw if not found Type type; - if (!this.typeCache.TryGetValue(typeName, out type)) + if (!TypeCache.TryGetValue(typeName, out type)) { var buffer = new byte[typeName.Count]; Buffer.BlockCopy(typeName.Array, typeName.Offset, buffer, 0, buffer.Length); @@ -287,18 +287,18 @@ private object DeserializeByTypeName(ArraySegment typeName, ref MessagePac } } - this.typeCache.TryAdd(buffer, type); + TypeCache.TryAdd(buffer, type); } options.ThrowIfDeserializingTypeIsDisallowed(type); var formatter = options.Resolver.GetFormatterDynamicWithVerify(type); - if (!this.deserializers.TryGetValue(type, out DeserializeMethod deserializeMethod)) + if (!Deserializers.TryGetValue(type, out DeserializeMethod deserializeMethod)) { - lock (this.deserializers) + lock (Deserializers) { - if (!this.deserializers.TryGetValue(type, out deserializeMethod)) + if (!Deserializers.TryGetValue(type, out deserializeMethod)) { TypeInfo ti = type.GetTypeInfo(); @@ -323,7 +323,7 @@ private object DeserializeByTypeName(ArraySegment typeName, ref MessagePac deserializeMethod = Expression.Lambda(body, param0, param1, param2).Compile(); - this.deserializers.TryAdd(type, deserializeMethod); + Deserializers.TryAdd(type, deserializeMethod); } } } diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTypelessTests.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTypelessTests.cs index 4364ef90f..995aaa6c2 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTypelessTests.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/MessagePackSerializerTypelessTests.cs @@ -6,6 +6,7 @@ using System; using System.Runtime.Serialization; using MessagePack; +using MessagePack.Formatters; using MessagePack.Resolvers; using Xunit; using Xunit.Abstractions; @@ -104,6 +105,14 @@ public void PrimitiveIntTypePreservation(object boxedValue) Assert.IsType(boxedValue.GetType(), roundTripValue); } + [Fact] + public void TypelessFormatterAsAttribute() + { + byte[] msgpack = MessagePackSerializer.Serialize(new ClassWithTypelessField { Value = "hi" }, MessagePackSerializerOptions.Standard); + var deserialized = MessagePackSerializer.Deserialize(msgpack, MessagePackSerializerOptions.Standard); + Assert.Equal("hi", deserialized.Value); + } + public class MyObject { public object SomeValue { get; set; } @@ -165,6 +174,14 @@ public class TypelessNonAbstract : TypelessAbstract { public int Y { get; set; } } + + [MessagePackObject] + public class ClassWithTypelessField + { + [Key("Value")] + [MessagePackFormatter(typeof(TypelessFormatter))] + public object Value; + } } #endif diff --git a/src/MessagePack/PublicAPI.Unshipped.txt b/src/MessagePack/PublicAPI.Unshipped.txt index e07f74a8e..d31186945 100644 --- a/src/MessagePack/PublicAPI.Unshipped.txt +++ b/src/MessagePack/PublicAPI.Unshipped.txt @@ -36,6 +36,7 @@ MessagePack.Formatters.ReadOnlySequenceFormatter.Serialize(ref MessagePack.Me MessagePack.Formatters.TypeFormatter MessagePack.Formatters.TypeFormatter.Deserialize(ref MessagePack.MessagePackReader reader, MessagePack.MessagePackSerializerOptions options) -> T MessagePack.Formatters.TypeFormatter.Serialize(ref MessagePack.MessagePackWriter writer, T value, MessagePack.MessagePackSerializerOptions options) -> void +MessagePack.Formatters.TypelessFormatter.TypelessFormatter() -> void MessagePack.ImmutableCollection.ImmutableArrayFormatter MessagePack.ImmutableCollection.ImmutableArrayFormatter.Deserialize(ref MessagePack.MessagePackReader reader, MessagePack.MessagePackSerializerOptions options) -> System.Collections.Immutable.ImmutableArray MessagePack.ImmutableCollection.ImmutableArrayFormatter.ImmutableArrayFormatter() -> void From 185e123c984d5786018782470403665ddcd4c423 Mon Sep 17 00:00:00 2001 From: Degant Puri Date: Mon, 9 Nov 2020 10:48:46 -0800 Subject: [PATCH 14/18] UriFormatter should use Uri.OriginalString when serializing --- .../Formatters/StandardClassLibraryFormatter.cs | 2 +- .../Assets/Scripts/Tests/ShareTests/FormatterTest.cs | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/StandardClassLibraryFormatter.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/StandardClassLibraryFormatter.cs index db56627e6..00c81a28b 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/StandardClassLibraryFormatter.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/StandardClassLibraryFormatter.cs @@ -300,7 +300,7 @@ public void Serialize(ref MessagePackWriter writer, Uri value, MessagePackSerial } else { - writer.Write(value.ToString()); + writer.Write(value.OriginalString); } } diff --git a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/FormatterTest.cs b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/FormatterTest.cs index f85d5f765..d2b18a795 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/FormatterTest.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/Tests/ShareTests/FormatterTest.cs @@ -294,11 +294,14 @@ public void DecimalLang() } } - [Fact] - public void UriTest_Absolute() + [Theory] + [InlineData("http://google.com/")] + [InlineData("http://google.com:80/")] + [InlineData("https://example.com:443/")] + public void UriTest_Absolute(string url) { - var absolute = new Uri("http://google.com/"); - this.Convert(absolute).ToString().Is("http://google.com/"); + var absolute = new Uri(url); + this.Convert(absolute).OriginalString.Is(url); } [SkippableFact] From 06c98de2450cd1a6acd0fb43d66ea943a2342626 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 10 Nov 2020 21:41:54 -0700 Subject: [PATCH 15/18] Simplify #if netcoreapp filters This allows code that compiles for netcoreapp3.1 or later to still execute the optimized code that is intended for .NET Core. --- .../MessagePack/Formatters/StandardClassLibraryFormatter.cs | 4 ++-- .../Assets/Scripts/MessagePack/MessagePackReader.cs | 2 +- .../Assets/Scripts/MessagePack/StringEncoding.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/StandardClassLibraryFormatter.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/StandardClassLibraryFormatter.cs index 00c81a28b..a227aaca2 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/StandardClassLibraryFormatter.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Formatters/StandardClassLibraryFormatter.cs @@ -476,7 +476,7 @@ private BigIntegerFormatter() public void Serialize(ref MessagePackWriter writer, System.Numerics.BigInteger value, MessagePackSerializerOptions options) { -#if NETCOREAPP2_1 +#if NETCOREAPP if (!writer.OldSpec) { // try to get bin8 buffer. @@ -504,7 +504,7 @@ public void Serialize(ref MessagePackWriter writer, System.Numerics.BigInteger v public System.Numerics.BigInteger Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { ReadOnlySequence bytes = reader.ReadBytes().Value; -#if NETCOREAPP2_1 +#if NETCOREAPP if (bytes.IsSingleSegment) { return new System.Numerics.BigInteger(bytes.First.Span); diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackReader.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackReader.cs index a2e5a946f..e8a01fdfb 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackReader.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/MessagePackReader.cs @@ -1109,7 +1109,7 @@ private string ReadStringSlow(int byteLength) int bytesRead = Math.Min(remainingByteLength, this.reader.UnreadSpan.Length); remainingByteLength -= bytesRead; bool flush = remainingByteLength == 0; -#if NETCOREAPP2_1 +#if NETCOREAPP initializedChars += decoder.GetChars(this.reader.UnreadSpan.Slice(0, bytesRead), charArray.AsSpan(initializedChars), flush); #else unsafe diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/StringEncoding.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/StringEncoding.cs index db8115a39..0be42149d 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/StringEncoding.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/StringEncoding.cs @@ -13,7 +13,7 @@ internal static class StringEncoding { internal static readonly Encoding UTF8 = new UTF8Encoding(false); -#if !NETCOREAPP2_1 // Define the extension method only where an instance method does not already exist. +#if !NETCOREAPP // Define the extension method only where an instance method does not already exist. internal static unsafe string GetString(this Encoding encoding, ReadOnlySpan bytes) { if (bytes.Length == 0) From 0f7a371ec7219497287499a41338756e1b54e389 Mon Sep 17 00:00:00 2001 From: neuecc Date: Wed, 11 Nov 2020 16:37:27 +0900 Subject: [PATCH 16/18] fix MessagePackWindow mpc invoke command --- .../Assets/Scripts/MessagePack/Unity/MessagePackWindow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Unity/MessagePackWindow.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Unity/MessagePackWindow.cs index 99a58c1b3..c9a7080fa 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Unity/MessagePackWindow.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Unity/MessagePackWindow.cs @@ -150,7 +150,7 @@ async void OnGUI() invokingMpc = true; try { - var log = await ProcessHelper.InvokeProcessStartAsync("dotnet", "mpc " + commnadLineArguments); + var log = await ProcessHelper.InvokeProcessStartAsync("mpc " + commnadLineArguments); UnityEngine.Debug.Log(log); } finally From f2b42ec6242cffb23ca34222c64ff683780e93d8 Mon Sep 17 00:00:00 2001 From: neuecc Date: Wed, 11 Nov 2020 17:54:10 +0900 Subject: [PATCH 17/18] ReadMe, record support --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index c8cf1f2de..115696777 100644 --- a/README.md +++ b/README.md @@ -403,6 +403,16 @@ public struct Point } ``` +C# 9.0 record with primary constructor is similar immutable object, also supports serialize/deserialize. + +```csharp +// use key as property name +[MessagePackObject(true)]public record Point(int X, int Y); + +// use property: to set KeyAttribute +[MessagePackObject] public record Point([property:Key(0)] int X, [property: Key(1)] int Y); +``` + ## Serialization Callback Objects implementing the `IMessagePackSerializationCallbackReceiver` interface will received `OnBeforeSerialize` and `OnAfterDeserialize` calls during serialization/deserialization. From 978fa23c51c7ef8abb35e8a57f5830ad888ce4fd Mon Sep 17 00:00:00 2001 From: neuecc Date: Wed, 11 Nov 2020 18:11:18 +0900 Subject: [PATCH 18/18] fix arg --- .../Assets/Scripts/MessagePack/Unity/MessagePackWindow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Unity/MessagePackWindow.cs b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Unity/MessagePackWindow.cs index c9a7080fa..013ad7967 100644 --- a/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Unity/MessagePackWindow.cs +++ b/src/MessagePack.UnityClient/Assets/Scripts/MessagePack/Unity/MessagePackWindow.cs @@ -150,7 +150,7 @@ async void OnGUI() invokingMpc = true; try { - var log = await ProcessHelper.InvokeProcessStartAsync("mpc " + commnadLineArguments); + var log = await ProcessHelper.InvokeProcessStartAsync("mpc", commnadLineArguments); UnityEngine.Debug.Log(log); } finally