From c3171b56ce0b3ebfeddebeb7d8fc25fb562c31a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Tue, 30 Dec 2025 00:18:45 +0400 Subject: [PATCH 01/27] perf(MemoryStreamReader.cs): Removed unnecessary memory allocation and copying --- Shared/MessagePack/Dto/ArraySegment.cs | 2 +- .../MessagePack/Stream/MemoryStreamReader.cs | 57 ++++--------------- 2 files changed, 13 insertions(+), 46 deletions(-) diff --git a/Shared/MessagePack/Dto/ArraySegment.cs b/Shared/MessagePack/Dto/ArraySegment.cs index a02e865..f3912dc 100644 --- a/Shared/MessagePack/Dto/ArraySegment.cs +++ b/Shared/MessagePack/Dto/ArraySegment.cs @@ -183,7 +183,7 @@ protected override void StartTokenGathering() public class ArraySegmentEnumerator : IEnumerator { private int _position = -1; - private ArraySegment _arraySegment; + private readonly ArraySegment _arraySegment; internal ArraySegmentEnumerator(ArraySegment arraySegment) { diff --git a/Shared/MessagePack/Stream/MemoryStreamReader.cs b/Shared/MessagePack/Stream/MemoryStreamReader.cs index d1c94b3..432c364 100644 --- a/Shared/MessagePack/Stream/MemoryStreamReader.cs +++ b/Shared/MessagePack/Stream/MemoryStreamReader.cs @@ -5,7 +5,6 @@ using System; using System.IO; #endif -using System.Collections; using nanoFramework.MessagePack.Dto; using nanoFramework.MessagePack.Utility; @@ -14,15 +13,11 @@ namespace nanoFramework.MessagePack.Stream internal sealed class MemoryStreamReader : BaseReader, IDisposable { private readonly MemoryStream _stream; - private readonly ArrayList _bytesGatheringBuffer; - - private long _bytesGatheringBufferLength = 0; - private bool _bytesGatheringInProgress; + private long _gatheringStartPosition; public MemoryStreamReader(MemoryStream stream) { _stream = stream; - _bytesGatheringBuffer = new ArrayList(); } public override byte ReadByte() @@ -33,42 +28,18 @@ public override byte ReadByte() throw ExceptionUtility.NotEnoughBytes(0, 1); } - var result = (byte)temp; - if (_bytesGatheringInProgress) - { - _bytesGatheringBuffer.Add(new byte[] { result }); - _bytesGatheringBufferLength++; - } - - return result; + return (byte)temp; } public override ArraySegment ReadBytes(uint length) { var buffer = ReadBytesInternal(length); - - if (_bytesGatheringInProgress) - { - _bytesGatheringBuffer.Add(buffer); - _bytesGatheringBufferLength += buffer.Length; - } - return buffer; } public override void Seek(long offset, SeekOrigin origin) { - if (_bytesGatheringInProgress) - { - var buffer = ReadBytesInternal((uint)offset); - - _bytesGatheringBuffer.Add(buffer); - _bytesGatheringBufferLength += buffer.Length; - } - else - { - _stream.Seek(offset, origin); - } + _stream.Seek(offset, origin); } public void Dispose() @@ -92,16 +63,14 @@ private byte[] ReadBytesInternal(uint length) { if (_stream.Position <= _stream.Length) { - _bytesGatheringInProgress = false; - - byte[] result = new byte[_bytesGatheringBufferLength]; - - int destinationOffset = 0; - foreach (byte[] part in _bytesGatheringBuffer) - { - Array.Copy(part, 0, result, destinationOffset, part.Length); - destinationOffset += part.Length; - } + long currentPosition = _stream.Position; + long bytesGathered = currentPosition - _gatheringStartPosition; + + byte[] result = new byte[bytesGathered]; + + _stream.Position = _gatheringStartPosition; + _stream.Read(result, 0, result.Length); + _stream.Position = currentPosition; return new ArraySegment(result, 0, result.Length); } @@ -113,9 +82,7 @@ private byte[] ReadBytesInternal(uint length) protected override void StartTokenGathering() { - _bytesGatheringInProgress = true; - _bytesGatheringBuffer.Clear(); - _bytesGatheringBufferLength = 0; + _gatheringStartPosition = _stream.Position; } } } From d9ad76ba05988bab0ab80863e0e4903dd170c67b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 31 Dec 2025 13:07:39 +0400 Subject: [PATCH 02/27] Update MemoryStreamReader.cs Correction based on Copilot's comments --- .../MessagePack/Stream/MemoryStreamReader.cs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Shared/MessagePack/Stream/MemoryStreamReader.cs b/Shared/MessagePack/Stream/MemoryStreamReader.cs index 432c364..693e135 100644 --- a/Shared/MessagePack/Stream/MemoryStreamReader.cs +++ b/Shared/MessagePack/Stream/MemoryStreamReader.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #if NANOFRAMEWORK_1_0 @@ -61,28 +61,28 @@ private byte[] ReadBytesInternal(uint length) #nullable enable protected override ArraySegment? StopTokenGathering() { - if (_stream.Position <= _stream.Length) + if (_stream.Position <= _stream.Length && _gatheringStartPosition >= 0) { long currentPosition = _stream.Position; long bytesGathered = currentPosition - _gatheringStartPosition; - - byte[] result = new byte[bytesGathered]; - - _stream.Position = _gatheringStartPosition; - _stream.Read(result, 0, result.Length); - _stream.Position = currentPosition; - return new ArraySegment(result, 0, result.Length); - } - else - { - return null; + if (bytesGathered > 0) + { + _stream.Position = _gatheringStartPosition; + byte[] result = ReadBytesInternal((uint)bytesGathered); + _stream.Position = currentPosition; + + return new ArraySegment(result, 0, result.Length); + } } + + return null; + } protected override void StartTokenGathering() { - _gatheringStartPosition = _stream.Position; + _gatheringStartPosition = _stream.Position; } } } From 6754763bbeb6b3fc1d5328f78cff8927974554a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Sun, 11 Jan 2026 19:02:01 +0400 Subject: [PATCH 03/27] fix(Fixed a typo in the method name 'GetMassagePackObjectTokens') perf(Simplified the cycle in the method 'ReadMap') perf(Duplicate error message lines have been removed) --- Shared/MessagePack/ConverterContext.cs | 2 +- .../Extensions/ObjectTokenHelper.cs | 21 +++++++++++-------- .../MessagePack/Utility/ExceptionUtility.cs | 4 ++-- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Shared/MessagePack/ConverterContext.cs b/Shared/MessagePack/ConverterContext.cs index babced9..9aab239 100644 --- a/Shared/MessagePack/ConverterContext.cs +++ b/Shared/MessagePack/ConverterContext.cs @@ -264,7 +264,7 @@ internal static void SerializeObject(Type type, object value, IMessagePackWriter return ArrayConverter.Read(reader, type); } - var objectMap = reader.GetMassagePackObjectTokens(); + var objectMap = reader.GetMessagePackObjectTokens(); if (objectMap != null && objectMap is Hashtable targetObjectMap) { var targetObject = CreateInstance(type); diff --git a/Shared/MessagePack/Extensions/ObjectTokenHelper.cs b/Shared/MessagePack/Extensions/ObjectTokenHelper.cs index 5070f44..14c2749 100644 --- a/Shared/MessagePack/Extensions/ObjectTokenHelper.cs +++ b/Shared/MessagePack/Extensions/ObjectTokenHelper.cs @@ -3,6 +3,9 @@ using System.Collections; using System.Diagnostics.CodeAnalysis; +using nanoFramework.MessagePack.Converters; +using nanoFramework.MessagePack.Dto; +using nanoFramework.MessagePack.Exceptions; using nanoFramework.MessagePack.Stream; namespace nanoFramework.MessagePack.Extensions @@ -10,23 +13,23 @@ namespace nanoFramework.MessagePack.Extensions internal static class ObjectTokenHelper { #nullable enable - internal static Hashtable? GetMassagePackObjectTokens([NotNull] this IMessagePackReader reader) + internal static Hashtable? GetMessagePackObjectTokens([NotNull] this IMessagePackReader reader) { - var length = reader.ReadMapLength(); + int length = (int)reader.ReadMapLength(); return length > 0 ? reader.ReadMap(length) : null; } - private static Hashtable ReadMap(this IMessagePackReader reader, uint length) + private static Hashtable ReadMap(this IMessagePackReader reader, int length) { - var map = new Hashtable(); + var map = new Hashtable(length); - var stringConverter = ConverterContext.GetConverter(typeof(string)); - for (var i = 0; i < length; i++) + IConverter stringConverter = ConverterContext.GetConverter(typeof(string)); + while (length-- > 0) { - var key = stringConverter.Read(reader); - var value = reader.ReadToken(); + string key = (stringConverter.Read(reader) as string) ?? throw new SerializationException("Map key must be a string."); + ArraySegment? value = reader.ReadToken(); - map[key!] = value; + map[key] = value; } return map; diff --git a/Shared/MessagePack/Utility/ExceptionUtility.cs b/Shared/MessagePack/Utility/ExceptionUtility.cs index 5ddf81c..4e3345c 100644 --- a/Shared/MessagePack/Utility/ExceptionUtility.cs +++ b/Shared/MessagePack/Utility/ExceptionUtility.cs @@ -21,7 +21,7 @@ public static Exception CantReadStringAsBinary() public static Exception NotEnoughBytes(int actual, int expected) { - return new SerializationException($"Expected {expected} bytes, got {actual} bytes."); + return NotEnoughBytes((long)actual, (long)expected); } public static Exception NotEnoughBytes(long actual, long expected) @@ -41,7 +41,7 @@ public static Exception IntDeserializationFailure(DataTypes type) public static Exception IntSerializationFailure(long value) { - return new SerializationException($"Can't serialize {value}"); + return IntSerializationFailure((ulong) value); } public static Exception IntSerializationFailure(ulong value) From 02842390bfcc073336dc133cc2e324869719274d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Tue, 3 Feb 2026 10:55:38 +0400 Subject: [PATCH 04/27] perf(Direct comparison of types when searching for converters); perf(Properties are extracted from types in a separate class); perf(Improved retrieval of an object by MessagePack data type); perf(Duplicate and unused code has been removed); perf(Improved information about MessagePack data type errors in converters); --- Shared/MessagePack/ConverterContext.cs | 403 +++++++++--------- .../MessagePack/Converters/ArrayConverter.cs | 95 ----- .../Converters/ArrayListConverter.cs | 10 +- .../MessagePack/Converters/BinaryConverter.cs | 157 ++----- .../MessagePack/Converters/BoolConverter.cs | 42 +- .../MessagePack/Converters/ByteConverter.cs | 55 ++- .../MessagePack/Converters/CharConverter.cs | 41 +- .../Converters/DateTimeConverter.cs | 48 ++- .../MessagePack/Converters/DoubleConverter.cs | 100 +++-- .../MessagePack/Converters/FloatConverter.cs | 84 ++-- .../MessagePack/Converters/GuidConverter.cs | 41 +- Shared/MessagePack/Converters/IntConverter.cs | 46 +- .../MessagePack/Converters/LongConverter.cs | 46 +- Shared/MessagePack/Converters/MapConverter.cs | 59 ++- .../MessagePack/Converters/SbyteConverter.cs | 45 +- .../MessagePack/Converters/ShortConverter.cs | 57 ++- .../Converters/SimpleArrayConverter.cs | 104 +++-- .../MessagePack/Converters/StringConverter.cs | 28 +- .../Converters/TimeSpanConverter.cs | 43 +- .../MessagePack/Converters/UintConverter.cs | 51 ++- .../MessagePack/Converters/UlongConverter.cs | 52 ++- .../MessagePack/Converters/UshortConverter.cs | 48 ++- Shared/MessagePack/Dto/ArraySegment.cs | 2 +- Shared/MessagePack/Dto/MemberMapping.cs | 114 ++--- Shared/MessagePack/Dto/MemberPropertyInfo.cs | 174 ++++++++ Shared/MessagePack/Dto/TypeValueDictionary.cs | 198 +++++++++ .../Exceptions/ConverterNotFoundException.cs | 2 + .../Extensions/DataTypesExtension.cs | 4 +- .../Extensions/NumberConverterHelper.cs | 45 +- .../Extensions/ObjectTokenHelper.cs | 16 +- Shared/MessagePack/MessagePack.projitems | 3 +- Shared/MessagePack/MessagePackSerializer.cs | 5 +- Shared/MessagePack/Stream/BaseReader.cs | 7 +- .../MessagePack/Stream/MemoryStreamReader.cs | 12 +- .../MessagePack/Stream/MemoryStreamWriter.cs | 4 +- .../MessagePack/Utility/ExceptionUtility.cs | 22 +- Shared/MessagePack/Utility/FieldUtility.cs | 28 +- Shared/MessagePack/Utility/PropertyUtility.cs | 108 +---- 38 files changed, 1353 insertions(+), 1046 deletions(-) delete mode 100644 Shared/MessagePack/Converters/ArrayConverter.cs create mode 100644 Shared/MessagePack/Dto/MemberPropertyInfo.cs create mode 100644 Shared/MessagePack/Dto/TypeValueDictionary.cs diff --git a/Shared/MessagePack/ConverterContext.cs b/Shared/MessagePack/ConverterContext.cs index 9aab239..97e0245 100644 --- a/Shared/MessagePack/ConverterContext.cs +++ b/Shared/MessagePack/ConverterContext.cs @@ -1,9 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if NANOFRAMEWORK_1_0 using System; +#endif using System.Collections; -using System.Diagnostics; using System.Runtime.CompilerServices; using nanoFramework.MessagePack.Converters; using nanoFramework.MessagePack.Dto; @@ -11,12 +12,13 @@ using nanoFramework.MessagePack.Extensions; using nanoFramework.MessagePack.Stream; using nanoFramework.MessagePack.Utility; -#if !NANOFRAMEWORK_1_0 -using System.Collections.Concurrent; -#endif + namespace nanoFramework.MessagePack { +#nullable enable + internal delegate object? DataTypesActionDelegate(byte dataType, IMessagePackReader reader); + /// /// Context by serialization/deserialization /// @@ -24,66 +26,100 @@ public static class ConverterContext { private static readonly Type[] s_emptyTypes = new Type[0]; private static readonly NullConverter s_nullConverter = new(); - private static readonly MapConverter s_mapConverter = new(); - private static readonly ArrayConverter s_arrayConverter = new(); - -#if NANOFRAMEWORK_1_0 - private static readonly Hashtable s_mappingDictionary = new(); -#else - private static readonly ConcurrentDictionary s_mappingDictionary = new(); -#endif - - private static readonly Hashtable s_conversionTable = new() + private static IConverter? s_longConverter = new LongConverter(); + private static IConverter? s_stringConverter = new StringConverter(); + private static IConverter? s_binaryConverter = new BinaryConverter(); + private static IConverter? s_ushortConverter = new UshortConverter(); + private static readonly DataTypesActionDelegate[] s_highBitsDataTypesActions = new DataTypesActionDelegate[] { - { typeof(IDictionary).FullName!, s_mapConverter }, - { typeof(Hashtable).FullName!, s_mapConverter }, - { typeof(ArrayList).FullName!, new ArrayListConverter() }, - { typeof(short).FullName!, new ShortConverter() }, - { typeof(ushort).FullName!, new UshortConverter() }, - { typeof(int).FullName!, new IntConverter() }, - { typeof(uint).FullName!, new UintConverter() }, - { typeof(long).FullName!, new LongConverter() }, - { typeof(ulong).FullName!, new UlongConverter() }, - { typeof(byte).FullName!, new ByteConverter() }, - { typeof(sbyte).FullName!, new SbyteConverter() }, - { typeof(float).FullName!, new FloatConverter() }, - { typeof(double).FullName!, new DoubleConverter() }, - { typeof(bool).FullName!, new BoolConverter() }, - { typeof(string).FullName!, new StringConverter() }, - { typeof(TimeSpan).FullName!, new TimeSpanConverter() }, - { typeof(DateTime).FullName!, new DateTimeConverter() }, - { typeof(char).FullName!, new CharConverter() }, - { typeof(Guid).FullName!, new GuidConverter() }, - { typeof(byte[]).FullName!, new BinaryConverter() }, - { typeof(int[]).FullName!, new SimpleArrayConverter(typeof(int)) }, - { typeof(uint[]).FullName!, new SimpleArrayConverter(typeof(uint)) }, - { typeof(long[]).FullName!, new SimpleArrayConverter(typeof(long)) }, - { typeof(ulong[]).FullName!, new SimpleArrayConverter(typeof(ulong)) }, - { typeof(float[]).FullName!, new SimpleArrayConverter(typeof(float)) }, - { typeof(double[]).FullName!, new SimpleArrayConverter(typeof(double)) }, - { typeof(char[]).FullName!, new SimpleArrayConverter(typeof(char)) }, - { typeof(string[]).FullName!, new SimpleArrayConverter(typeof(string)) }, - { typeof(Guid[]).FullName!, new SimpleArrayConverter(typeof(Guid)) }, - { typeof(sbyte[]).FullName!, new SimpleArrayConverter(typeof(sbyte)) }, - { typeof(DateTime[]).FullName!, new SimpleArrayConverter(typeof(DateTime)) }, - { typeof(TimeSpan[]).FullName!, new SimpleArrayConverter(typeof(TimeSpan)) }, - { typeof(bool[]).FullName!, new SimpleArrayConverter(typeof(bool)) }, - { typeof(short[]).FullName!, new SimpleArrayConverter(typeof(short)) }, - { typeof(ushort[]).FullName!, new SimpleArrayConverter(typeof(ushort)) } + //// 0x8... => DataTypes.FixMap + (dataType, reader) => MapConverter.ReadMap(reader, dataType - (int)DataTypes.FixMap), + //// 0x9... => DataTypes.FixArray + (dataType, reader) => ArrayListConverter.ReadArrayList(reader, dataType - (int)DataTypes.FixArray), + //// 0xA... => DataTypes.FixStr + (dataType, reader) => Converters.StringConverter.ReadString(reader, dataType - (uint)DataTypes.FixStr), + //// 0xB... <= DataTypes.FixStr + (dataType, reader) => Converters.StringConverter.ReadString(reader, dataType - (uint)DataTypes.FixStr), + //// 0xC... => DataTypes.Null, DataTypes.False, ..... + (dataType, reader) => ReadCObject(dataType, reader), + //// 0xD... => DataTypes.Int8, DataTypes.Int16, ..... + (dataType, reader) => ReadDObject(dataType, reader), + //// 0xE... => DataTypes.NegativeFixNum + (dataType, reader) => (sbyte)(dataType - 1 - byte.MaxValue), + //// 0xF... <= DataTypes.NegativeFixNum + (dataType, reader) => (sbyte)(dataType - 1 - byte.MaxValue) + }; + private static readonly TypeValueDictionary s_mappingDictionary = new(); + private static readonly TypeValueDictionary s_conversionTable = new() + { + {typeof(string), s_stringConverter }, + {typeof(Hashtable), new MapConverter()}, + {typeof(IDictionary), new MapConverter() }, + {typeof(long), s_longConverter}, + {typeof(ulong), new UlongConverter()}, + {typeof(byte), new ByteConverter()}, + {typeof(int), new IntConverter()}, + {typeof(uint), new UintConverter()}, + {typeof(ArrayList), new ArrayListConverter()}, + {typeof(short), new ShortConverter()}, + {typeof(ushort), s_ushortConverter}, + {typeof(sbyte), new SbyteConverter()}, + {typeof(float), new FloatConverter()}, + {typeof(double), new DoubleConverter()}, + {typeof(bool), new BoolConverter()}, + {typeof(char), new CharConverter()}, + {typeof(Guid),new GuidConverter()}, + {typeof(DateTime), new DateTimeConverter()}, + {typeof(TimeSpan), new TimeSpanConverter()}, + {typeof(byte[]), s_binaryConverter}, + {typeof(int[]), new SimpleArrayConverter(typeof(int))}, + {typeof(uint[]), new SimpleArrayConverter(typeof(uint))}, + {typeof(long[]), new SimpleArrayConverter(typeof(long))}, + {typeof(ulong[]), new SimpleArrayConverter(typeof(ulong))}, + {typeof(float[]), new SimpleArrayConverter(typeof(float))}, + {typeof(double[]), new SimpleArrayConverter(typeof(double))}, + {typeof(char[]), new SimpleArrayConverter(typeof(char))}, + {typeof(string[]), new SimpleArrayConverter(typeof(string))}, + {typeof(Guid[]), new SimpleArrayConverter(typeof(Guid))}, + {typeof(sbyte[]), new SimpleArrayConverter(typeof(sbyte))}, + {typeof(DateTime[]), new SimpleArrayConverter(typeof(DateTime))}, + {typeof(TimeSpan[]), new SimpleArrayConverter(typeof(TimeSpan))}, + {typeof(bool[]), new SimpleArrayConverter(typeof(bool))}, + {typeof(short[]), new SimpleArrayConverter(typeof(short))}, + {typeof(ushort[]), new SimpleArrayConverter(typeof(ushort))} }; /// - /// Null value converter. + /// value converter. /// public static IConverter NullConverter => s_nullConverter; + /// + /// value converter. + /// + internal static IConverter LongConverter => s_longConverter ?? throw ExceptionUtility.ConverterNotFound(typeof(long)); + + /// + /// value converter. + /// + internal static IConverter StringConverter => s_stringConverter ?? throw ExceptionUtility.ConverterNotFound(typeof(string)); + + /// + /// array converter. + /// + internal static IConverter BinaryConverter => s_binaryConverter ?? throw ExceptionUtility.ConverterNotFound(typeof(byte[])); + + /// + /// value converter. + /// + internal static IConverter UshortConverter => s_ushortConverter ?? throw ExceptionUtility.ConverterNotFound(typeof(ushort)); + /// /// Adds new converter to collection to support more types. /// /// Type of object. /// Converter instance which will be used to convert . /// Converter by type not support in convertors table. - [MethodImpl(MethodImplOptions.Synchronized)] public static void Add(Type type, IConverter converter) { if (type == typeof(object)) @@ -91,7 +127,9 @@ public static void Add(Type type, IConverter converter) throw new NotSupportedException(); } - s_conversionTable.Add(type.FullName!, converter); + s_conversionTable.Add(type, converter); + + UpdateFrequentlyUsedConverter(type, converter); } /// @@ -100,7 +138,9 @@ public static void Add(Type type, IConverter converter) /// Type of object. public static void Remove(Type type) { - s_conversionTable.Remove(type.FullName!); + s_conversionTable.Remove(type); + + UpdateFrequentlyUsedConverter(type, null); } /// @@ -108,95 +148,77 @@ public static void Remove(Type type) /// /// Type of object. /// Converter instance which will be used to convert . - [MethodImpl(MethodImplOptions.Synchronized)] public static void Replace(Type type, IConverter converter) { Remove(type); Add(type, converter); } - +#nullable enable /// /// Return converter by type. /// /// Type object from converter. /// Converter interface or null. /// If object type is . - public static IConverter GetConverter(Type type) + public static IConverter? GetConverter(Type type) { if (type == typeof(object)) { throw ExceptionUtility.ConverterNotFound(type); } - if (s_conversionTable.Contains(type.FullName!)) - { - return (IConverter)s_conversionTable[type.FullName!]!; - } - - return null!; + return (IConverter?)s_conversionTable[type]; } internal static Hashtable GetMappingsValues(Type targetType, object value) { - var memberMappings = GetMemberMapping(targetType); + MemberMapping[] memberMappings = GetMemberMapping(targetType); Hashtable result = new(); - foreach (var memberMapping in memberMappings) + for (int i = 0; i < memberMappings.Length; i++) { -#if NANOFRAMEWORK_1_0 - if (!memberMapping.OriginalName!.StartsWith(MemberMapping.SET_)) + if (memberMappings[i] is MemberMapping memberMapping) { -#endif - if (memberMapping.TryGetValue(value, out var memberValue) && memberValue != null) + if (memberMapping.TryGetValue(value, out object? memberValue) && memberValue != null) { - result.Add(memberMapping.Name!, memberValue); + result.Add(memberMapping.Name, memberValue); } -#if NANOFRAMEWORK_1_0 } -#endif } return result; } internal static void SetMappingsValues(Type targetType, object targetObject, Hashtable objectValuesMap) { - var memberMappings = GetMemberMapping(targetType); + MemberMapping[] memberMappings = GetMemberMapping(targetType); + + Type? preMemberValueMapType = null; + IConverter? converter = null; - foreach (var memberMapping in memberMappings) + for (int i = 0; i < memberMappings.Length; i++) { -#if NANOFRAMEWORK_1_0 - if (!memberMapping.OriginalName!.StartsWith(MemberMapping.GET_)) + if (memberMappings[i] is MemberMapping memberMapping) { -#endif - if (objectValuesMap.Contains(memberMapping.Name!)) + if (objectValuesMap[memberMapping.Name] is ArraySegment memberMapToken) { - var memberMpToken = (ArraySegment)objectValuesMap[memberMapping.Name!]!; - if (memberMpToken != null) + Type memberValueMapType = memberMapping.MemberType; + if (memberValueMapType != preMemberValueMapType) + { + converter = GetConverter(memberValueMapType); + preMemberValueMapType = memberValueMapType; + } + + if (converter != null) + { + memberMapping.SetValue(targetObject, converter.Read(memberMapToken)); + } + else { - var memberValueMapType = memberMapping.GetMemberType(); - var converter = GetConverter(memberValueMapType!); - if (converter != null) - { - memberMapping.SetValue(targetObject, converter.Read(memberMpToken)!); - } - else - { - if (memberValueMapType!.IsArray) - { - memberMapping.SetValue(targetObject, ArrayConverter.Read(memberMpToken, memberValueMapType)!); - } - else - { - - memberMapping.SetValue(targetObject, DeserializeObject(memberValueMapType!, memberMpToken)!); - } - } + memberMapping.SetValue(targetObject, DeserializeObject(memberValueMapType, memberMapToken)); } } -#if NANOFRAMEWORK_1_0 } -#endif } } @@ -208,14 +230,13 @@ internal static object CreateInstance(Type targetType) internal static MemberMapping[] GetMemberMapping(Type targetType) { -#if NANOFRAMEWORK_1_0 var cached = s_mappingDictionary[targetType]; - if (cached is not MemberMapping[] memberMappings) + if (cached is MemberMapping[] memberMappings) { -#else - if (!s_mappingDictionary.TryGetValue(targetType, out var memberMappings)) + return memberMappings; + } + else { -#endif var mappings = new ArrayList(); FieldUtility.Map(targetType, mappings); @@ -223,49 +244,46 @@ internal static MemberMapping[] GetMemberMapping(Type targetType) memberMappings = (MemberMapping[])mappings.ToArray(typeof(MemberMapping)); -#if NANOFRAMEWORK_1_0 - ThreadSafeAddItemCache(s_mappingDictionary, targetType, memberMappings); -#else - s_mappingDictionary.TryAdd(targetType, memberMappings); -#endif - } - - return memberMappings; + s_mappingDictionary[targetType] = memberMappings; + return memberMappings; + } } internal static void SerializeObject(Type type, object value, IMessagePackWriter writer) { - if (value is IDictionary || value is Hashtable) - { - s_mapConverter.Write(value, writer); - return; - } - if (type.IsArray) { - s_arrayConverter.Write(value, writer); + SimpleArrayConverter.Write((Array)value, null, writer); return; } + else + { + var objectMap = value; - var objectMap = GetMappingsValues(type, value); - s_mapConverter.Write(objectMap, writer); + if (type != typeof(IDictionary) && type != typeof(Hashtable)) + { + objectMap = GetMappingsValues(type, value); + } + + MapConverter.Write((IDictionary)objectMap, writer); + } } -#nullable enable + internal static object? DeserializeObject(Type type, IMessagePackReader reader) { - if (type.Name == typeof(IDictionary).Name || type.Name == typeof(Hashtable).Name) + if (type == typeof(IDictionary) || type == typeof(Hashtable)) { return MapConverter.Read(reader); } if (type.IsArray) { - return ArrayConverter.Read(reader, type); + return SimpleArrayConverter.Read(reader, type); } var objectMap = reader.GetMessagePackObjectTokens(); - if (objectMap != null && objectMap is Hashtable targetObjectMap) + if (objectMap is Hashtable targetObjectMap) { var targetObject = CreateInstance(type); SetMappingsValues(type, targetObject, targetObjectMap); @@ -273,96 +291,70 @@ internal static void SerializeObject(Type type, object value, IMessagePackWriter } else { +#if !NANOFRAMEWORK_1_0 throw new SerializationException($"Type {type.Name} can not by deserialize."); +#else + throw new SerializationException(type.Name); +#endif } } internal static object? GetObjectByDataType(IMessagePackReader reader) { - var type = reader.ReadDataType(); + DataTypes type = reader.ReadDataType(); + if (type.GetHighBits(1) == DataTypes.PositiveFixNum.GetHighBits(1)) + { + return (byte)type; + } + else + { + int highIndex = type.GetHighBits(4) - DataTypes.FixMap.GetHighBits(4); + return s_highBitsDataTypesActions[highIndex].Invoke((byte)type, reader); + } + } + private static object? ReadCObject(byte dataType, IMessagePackReader reader) + { + DataTypes type = (DataTypes)dataType; return type switch { DataTypes.Null => null, - DataTypes.True => true, DataTypes.False => false, - DataTypes.Double => NumberConverterHelper.ReadDouble(reader), + DataTypes.True => true, + DataTypes.Bin8 => reader.ReadBytes(reader.ReadByte()), + DataTypes.Bin16 => reader.ReadBytes(NumberConverterHelper.ReadUInt16(reader)), + DataTypes.Bin32 => reader.ReadBytes(NumberConverterHelper.ReadUInt32(reader)), + DataTypes.Timestamp96 => ReadDateTimeExt(type, reader), DataTypes.Single => NumberConverterHelper.ReadFloat(reader), - DataTypes.Str8 => StringConverter.ReadString(reader, NumberConverterHelper.ReadUInt8(reader)), - DataTypes.Str16 => StringConverter.ReadString(reader, NumberConverterHelper.ReadUInt16(reader)), - DataTypes.Str32 => StringConverter.ReadString(reader, NumberConverterHelper.ReadUInt32(reader)), - DataTypes.UInt8 => NumberConverterHelper.ReadUInt8(reader), - DataTypes.Int8 => (byte)NumberConverterHelper.ReadInt8(reader), + DataTypes.Double => NumberConverterHelper.ReadDouble(reader), + DataTypes.UInt8 => reader.ReadByte(), DataTypes.UInt16 => NumberConverterHelper.ReadUInt16(reader), - DataTypes.Int16 => NumberConverterHelper.ReadInt16(reader), DataTypes.UInt32 => NumberConverterHelper.ReadUInt32(reader), - DataTypes.Int32 => NumberConverterHelper.ReadInt32(reader), DataTypes.UInt64 => NumberConverterHelper.ReadUInt64(reader), - DataTypes.Int64 => NumberConverterHelper.ReadInt64(reader), - DataTypes.Bin8 => reader.ReadBytes(NumberConverterHelper.ReadUInt8(reader)), - DataTypes.Bin16 => reader.ReadBytes(NumberConverterHelper.ReadUInt16(reader)), - DataTypes.Bin32 => reader.ReadBytes(NumberConverterHelper.ReadUInt32(reader)), - DataTypes.Timestamp32 => ReadDateTimeExt(type, reader), - DataTypes.Timestamp64 => ReadDateTimeExt(type, reader), - DataTypes.Timestamp96 => ReadDateTimeExt(type, reader), - DataTypes.Array16 => ArrayListConverter.ReadArrayList(reader, NumberConverterHelper.ReadUInt16(reader)), - DataTypes.Array32 => ArrayListConverter.ReadArrayList(reader, NumberConverterHelper.ReadUInt32(reader)), - DataTypes.Map16 => MapConverter.ReadMap(reader, NumberConverterHelper.ReadUInt16(reader)), - DataTypes.Map32 => MapConverter.ReadMap(reader, NumberConverterHelper.ReadUInt32(reader)), - _ => ReadObject(type, reader), + _ => throw ExceptionUtility.BadTypeException((DataTypes)dataType, DataTypes.Null, DataTypes.False, DataTypes.True, DataTypes.Bin8, DataTypes.Bin16, DataTypes.Bin32, DataTypes.Timestamp96, DataTypes.Single, DataTypes.Double, DataTypes.UInt8, DataTypes.UInt16, DataTypes.UInt32, DataTypes.UInt64) }; } -#if NANOFRAMEWORK_1_0 - private static void ThreadSafeAddItemCache(Hashtable hashtable, object key, object value) + private static object? ReadDObject(byte dataType, IMessagePackReader reader) { - if (!hashtable.Contains(key)) - { - lock (s_mappingDictionary) - { - try - { - if (!hashtable.Contains(key)) - { - hashtable.Add(key, value); - } - } - catch (Exception ex) - { - Debug.WriteLine($"Error added key: '{key}', value: '{value}'\r\n{ex}"); - } - } - } - } -#endif - private static object ReadObject(DataTypes type, IMessagePackReader reader) - { - if (type.GetHighBits(3) == DataTypes.FixStr.GetHighBits(3)) - { - return StringConverter.ReadString(reader, type - DataTypes.FixStr); - } - - if (NumberConverterHelper.TryGetFixPositiveNumber(type, out var positive)) - { - return positive; - } - - if (NumberConverterHelper.TryGetNegativeNumber(type, out var negative)) - { - return negative; - } - - if (type.GetHighBits(4) == DataTypes.FixArray.GetHighBits(4)) - { - return ArrayListConverter.ReadArrayList(reader, type - DataTypes.FixArray); - } - - if (type.GetHighBits(4) == DataTypes.FixMap.GetHighBits(4)) + DataTypes type = (DataTypes)dataType; + return type switch { - return MapConverter.ReadMap(reader, type - DataTypes.FixMap); - } - - throw ExceptionUtility.BadTypeException(type); + DataTypes.Int8 => (byte)NumberConverterHelper.ReadInt8(reader), + DataTypes.Int16 => NumberConverterHelper.ReadInt16(reader), + DataTypes.Int32 => NumberConverterHelper.ReadInt32(reader), + DataTypes.Int64 => NumberConverterHelper.ReadInt64(reader), + DataTypes.Timestamp32 => ReadDateTimeExt(type, reader), + DataTypes.Timestamp64 => ReadDateTimeExt(type, reader), + DataTypes.Str8 => Converters.StringConverter.ReadString(reader, reader.ReadByte()), + DataTypes.Str16 => Converters.StringConverter.ReadString(reader, NumberConverterHelper.ReadUInt16(reader)), + DataTypes.Str32 => Converters.StringConverter.ReadString(reader, NumberConverterHelper.ReadUInt32(reader)), + DataTypes.Array16 => ArrayListConverter.ReadArrayList(reader, NumberConverterHelper.ReadUInt16(reader)), + DataTypes.Array32 => ArrayListConverter.ReadArrayList(reader, (int)NumberConverterHelper.ReadUInt32(reader)), + DataTypes.Map16 => MapConverter.ReadMap(reader, NumberConverterHelper.ReadUInt16(reader)), + DataTypes.Map32 => MapConverter.ReadMap(reader, NumberConverterHelper.ReadInt32(reader)), + _ => throw ExceptionUtility.BadTypeException((DataTypes)dataType, DataTypes.Int8, DataTypes.Int16, DataTypes.Int32, DataTypes.Int64, DataTypes.Timestamp32, DataTypes.Timestamp64, DataTypes.Str8, DataTypes.Str16, DataTypes.Str32, DataTypes.Array16, DataTypes.Array32, DataTypes.Map16, DataTypes.Map32) + }; } private static DateTime ReadDateTimeExt(DataTypes type, IMessagePackReader reader) @@ -402,5 +394,26 @@ private static DateTime ReadDateTimeExt(DataTypes type, IMessagePackReader reade return DateTime.UnixEpoch.AddSeconds(seconds).AddMilliseconds(nanoSeconds / 1000.0); } + + [MethodImpl(MethodImplOptions.Synchronized)] + private static void UpdateFrequentlyUsedConverter(Type type, IConverter? converter) + { + if (type == typeof(string)) + { + s_stringConverter = converter; + } + else if (type == typeof(long)) + { + s_longConverter = converter; + } + else if (type == typeof(ushort)) + { + s_ushortConverter = converter; + } + else if (type == typeof(byte[])) + { + s_binaryConverter = converter; + } + } } } diff --git a/Shared/MessagePack/Converters/ArrayConverter.cs b/Shared/MessagePack/Converters/ArrayConverter.cs deleted file mode 100644 index 3ab44fa..0000000 --- a/Shared/MessagePack/Converters/ArrayConverter.cs +++ /dev/null @@ -1,95 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections; -using System.Diagnostics.CodeAnalysis; -using nanoFramework.MessagePack.Stream; - -namespace nanoFramework.MessagePack.Converters -{ - /// - /// Composite array converter - /// - internal class ArrayConverter : IConverter - { - private static void Write(IList value, IMessagePackWriter writer) - { - if (value == null || value.Count < 1) - { - ConverterContext.NullConverter.Write(value, writer); - return; - } - - writer.WriteArrayHeader((uint)value.Count); - - var elementType = value[0]!.GetType(); - var elementConverter = ConverterContext.GetConverter(elementType); - if (elementConverter != null) - { - foreach (var element in value) - { - elementConverter.Write(element, writer); - } - } - else - { - foreach (var element in value) - { - ConverterContext.SerializeObject(elementType, element, writer); - } - } - - } - -#nullable enable - internal static IList? Read(IMessagePackReader reader, Type arrayType) - { - var length = (int)reader.ReadArrayLength(); - return length > 0 ? ReadArray(reader, length, arrayType) : null; - } - - private static Array ReadArray(IMessagePackReader reader, int length, Type arrayType) - { - var elementType = arrayType.GetElementType(); - var targetArray = (IList)Array.CreateInstance(elementType!, length); - if (elementType!.IsArray) - { - for (var i = 0; i < length; i++) - { - targetArray[i] = Read(reader, elementType); - } - } - else - { - var converter = ConverterContext.GetConverter(elementType); - if (converter != null) - { - for (var i = 0; i < length; i++) - { - targetArray[i] = converter.Read(reader); - } - } - else - { - for (var i = 0; i < length; i++) - { - targetArray[i] = ConverterContext.DeserializeObject(elementType, reader); - } - } - } - - return (Array)targetArray; - } - - public void Write(object? value, [NotNull] IMessagePackWriter writer) - { - Write((IList)value!, writer); - } - - object? IConverter.Read([NotNull] IMessagePackReader reader) - { - throw new NotImplementedException(); - } - } -} diff --git a/Shared/MessagePack/Converters/ArrayListConverter.cs b/Shared/MessagePack/Converters/ArrayListConverter.cs index b257bf9..5c4479c 100644 --- a/Shared/MessagePack/Converters/ArrayListConverter.cs +++ b/Shared/MessagePack/Converters/ArrayListConverter.cs @@ -37,15 +37,15 @@ private static void Write(ArrayList? value, IMessagePackWriter writer) private static ArrayList? Read(IMessagePackReader reader) { - var length = reader.ReadArrayLength(); - return ((long)length) > -1 ? ReadArrayList(reader, length) : null; + int length = (int)reader.ReadArrayLength(); + return length > -1 ? ReadArrayList(reader, length) : null; } - internal static ArrayList ReadArrayList(IMessagePackReader reader, uint length) + internal static ArrayList ReadArrayList(IMessagePackReader reader, int length) { var array = new ArrayList(); - for (var i = 0; i < length; i++) + while (length-- > 0) { array.Add(ConverterContext.GetObjectByDataType(reader)); } @@ -55,7 +55,7 @@ internal static ArrayList ReadArrayList(IMessagePackReader reader, uint length) public void Write(object? value, [NotNull] IMessagePackWriter writer) { - Write((ArrayList)value!, writer); + Write((ArrayList?)value, writer); } object? IConverter.Read([NotNull] IMessagePackReader reader) diff --git a/Shared/MessagePack/Converters/BinaryConverter.cs b/Shared/MessagePack/Converters/BinaryConverter.cs index 0713c67..e9b8d58 100644 --- a/Shared/MessagePack/Converters/BinaryConverter.cs +++ b/Shared/MessagePack/Converters/BinaryConverter.cs @@ -1,7 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if NANOFRAMEWORK_1_0 +using System; +#endif using System.Diagnostics.CodeAnalysis; +using nanoFramework.MessagePack.Dto; using nanoFramework.MessagePack.Extensions; using nanoFramework.MessagePack.Stream; using nanoFramework.MessagePack.Utility; @@ -10,14 +14,27 @@ namespace nanoFramework.MessagePack.Converters { internal class BinaryConverter : IConverter { - private readonly bool _compatibilityMode; - - public BinaryConverter(bool compatibilityMode = false) + private static void WriteBinaryHeaderAndLength(uint length, IMessagePackWriter writer) { - _compatibilityMode = compatibilityMode; + if (length <= byte.MaxValue) + { + writer.Write(DataTypes.Bin8); + writer.Write((byte)length); + } + else if (length <= ushort.MaxValue) + { + writer.Write(DataTypes.Bin16); + NumberConverterHelper.WriteUShortValue((ushort)length, writer); + } + else + { + writer.Write(DataTypes.Bin32); + NumberConverterHelper.WriteUIntValue(length, writer); + } } - private void Write(byte[] value, IMessagePackWriter writer) +#nullable enable + public void Write(object? value, [NotNull] IMessagePackWriter writer) { if (value == null) { @@ -25,31 +42,36 @@ private void Write(byte[] value, IMessagePackWriter writer) return; } - var valueLength = (uint)value.Length; - if (_compatibilityMode) + if (value is byte[] byteArray) { - WriteStringHeaderAndLength(valueLength, writer); + uint valueLength = (uint)byteArray.Length; + + WriteBinaryHeaderAndLength(valueLength, writer); + + writer.Write(byteArray); } else { - WriteBinaryHeaderAndLength(valueLength, writer); +#if NANOFRAMEWORK_1_0 + throw new ArgumentException(); +#else + throw new ArgumentException("The value must be of type byte[].", nameof(value)); +#endif } - - writer.Write(value); } - private byte[] Read(IMessagePackReader reader) + object? IConverter.Read([NotNull] IMessagePackReader reader) { - var type = reader.ReadDataType(); + DataTypes type = reader.ReadDataType(); uint length; switch (type) { case DataTypes.Null: - return null!; + return null; case DataTypes.Bin8: - length = NumberConverterHelper.ReadUInt8(reader); + length = reader.ReadByte(); break; case DataTypes.Bin16: @@ -60,113 +82,12 @@ private byte[] Read(IMessagePackReader reader) length = NumberConverterHelper.ReadUInt32(reader); break; - case DataTypes.Str8: - if (_compatibilityMode) - { - length = NumberConverterHelper.ReadUInt8(reader); - } - else - { - throw ExceptionUtility.CantReadStringAsBinary(); - } - - break; - - case DataTypes.Str16: - if (_compatibilityMode) - { - length = NumberConverterHelper.ReadUInt16(reader); - } - else - { - throw ExceptionUtility.CantReadStringAsBinary(); - } - - break; - - case DataTypes.Str32: - if (_compatibilityMode) - { - length = NumberConverterHelper.ReadUInt32(reader); - } - else - { - throw ExceptionUtility.CantReadStringAsBinary(); - } - - break; - default: - if ((type & DataTypes.FixStr) == DataTypes.FixStr) - { - if (_compatibilityMode) - { - length = (uint)(type & ~DataTypes.FixStr); - } - else - { - throw ExceptionUtility.CantReadStringAsBinary(); - } - } - else - { - throw ExceptionUtility.BadTypeException(type, DataTypes.Bin8, DataTypes.Bin16, DataTypes.Bin32, DataTypes.Null); - } - break; + throw ExceptionUtility.BadTypeException(type, DataTypes.Bin8, DataTypes.Bin16, DataTypes.Bin32, DataTypes.Null); } - var array = reader.ReadBytes(length); + ArraySegment array = reader.ReadBytes(length); return (byte[])array; } - - private static void WriteBinaryHeaderAndLength(uint length, IMessagePackWriter writer) - { - if (length <= byte.MaxValue) - { - writer.Write(DataTypes.Bin8); - NumberConverterHelper.WriteByteValue((byte)length, writer); - } - else if (length <= ushort.MaxValue) - { - writer.Write(DataTypes.Bin16); - NumberConverterHelper.WriteUShortValue((ushort)length, writer); - } - else - { - writer.Write(DataTypes.Bin32); - NumberConverterHelper.WriteUIntValue(length, writer); - } - } - - private static void WriteStringHeaderAndLength(uint length, IMessagePackWriter writer) - { - if (length <= 31) - { - writer.Write((byte)(((byte)DataTypes.FixStr + length) % 256)); - return; - } - - if (length <= ushort.MaxValue) - { - writer.Write(DataTypes.Str16); - NumberConverterHelper.WriteUShortValue((ushort)length, writer); - } - else - { - writer.Write(DataTypes.Str32); - NumberConverterHelper.WriteUIntValue((uint)length, writer); - } - } - -#nullable enable - public void Write(object? value, [NotNull] IMessagePackWriter writer) - { - Write((byte[])value!, writer); - } - - object? IConverter.Read([NotNull] IMessagePackReader reader) - { - return Read(reader); - } } } diff --git a/Shared/MessagePack/Converters/BoolConverter.cs b/Shared/MessagePack/Converters/BoolConverter.cs index 1de7ca3..4bd9c10 100644 --- a/Shared/MessagePack/Converters/BoolConverter.cs +++ b/Shared/MessagePack/Converters/BoolConverter.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if NANOFRAMEWORK_1_0 +using System; +#endif using System.Diagnostics.CodeAnalysis; using nanoFramework.MessagePack.Stream; using nanoFramework.MessagePack.Utility; @@ -9,14 +12,34 @@ namespace nanoFramework.MessagePack.Converters { internal class BoolConverter : IConverter { - private static void Write(bool value, IMessagePackWriter writer) +#nullable enable + public void Write(object? value, [NotNull] IMessagePackWriter writer) { - writer.Write(value ? DataTypes.True : DataTypes.False); + if (value == null) + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentNullException(); +#else + throw new ArgumentNullException(nameof(value)); +#endif + } + if (value is bool boolValue) + { + writer.Write(boolValue ? DataTypes.True : DataTypes.False); + } + else + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentException(); +#else + throw new ArgumentException("Value must be of type bool.", nameof(value)); +#endif + } } - private static bool Read(IMessagePackReader reader) + object? IConverter.Read([NotNull] IMessagePackReader reader) { - var type = reader.ReadDataType(); + DataTypes type = reader.ReadDataType(); return type switch { @@ -25,16 +48,5 @@ private static bool Read(IMessagePackReader reader) _ => throw ExceptionUtility.BadTypeException(type, DataTypes.True, DataTypes.False), }; } - -#nullable enable - public void Write(object? value, [NotNull] IMessagePackWriter writer) - { - Write((bool)value!, writer); - } - - object? IConverter.Read([NotNull] IMessagePackReader reader) - { - return Read(reader); - } } } diff --git a/Shared/MessagePack/Converters/ByteConverter.cs b/Shared/MessagePack/Converters/ByteConverter.cs index 1b93943..11a54a4 100644 --- a/Shared/MessagePack/Converters/ByteConverter.cs +++ b/Shared/MessagePack/Converters/ByteConverter.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if NANOFRAMEWORK_1_0 +using System; +#endif using System.Diagnostics.CodeAnalysis; using nanoFramework.MessagePack.Extensions; using nanoFramework.MessagePack.Stream; @@ -10,23 +13,44 @@ namespace nanoFramework.MessagePack.Converters { internal class ByteConverter : IConverter { - private static void Write(byte value, IMessagePackWriter writer) +#nullable enable + public void Write(object? value, [NotNull] IMessagePackWriter writer) { - // positive fixnum - if (value < 128L) + if (value == null) + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentNullException(); +#else + throw new ArgumentNullException(nameof(value)); +#endif + } + + if (value is byte byteValue) { - writer.Write(value); + // positive fixnum + if (byteValue < 128L) + { + writer.Write(byteValue); + } + else + { + writer.Write(DataTypes.UInt8); + writer.Write(byteValue); + } } else { - writer.Write(DataTypes.UInt8); - value.WriteByteValue(writer); +#if NANOFRAMEWORK_1_0 + throw new ArgumentException(); +#else + throw new ArgumentException("Value must be of type byte.", nameof(value)); +#endif } } - private static byte Read(IMessagePackReader reader) + object? IConverter.Read([NotNull] IMessagePackReader reader) { - var type = reader.ReadDataType(); + DataTypes type = reader.ReadDataType(); if (NumberConverterHelper.TryGetFixPositiveNumber(type, out byte temp)) { @@ -40,21 +64,10 @@ private static byte Read(IMessagePackReader reader) return type switch { - DataTypes.UInt8 => NumberConverterHelper.ReadUInt8(reader), + DataTypes.UInt8 => reader.ReadByte(), DataTypes.Int8 => (byte)NumberConverterHelper.ReadInt8(reader), - _ => throw ExceptionUtility.IntDeserializationFailure(type), + _ => throw ExceptionUtility.BadTypeException(type, DataTypes.PositiveFixNum, DataTypes.NegativeFixNum, DataTypes.UInt8, DataTypes.Int8), }; } - -#nullable enable - public void Write(object? value, [NotNull] IMessagePackWriter writer) - { - Write((byte)value!, writer); - } - - object? IConverter.Read([NotNull] IMessagePackReader reader) - { - return Read(reader); - } } } diff --git a/Shared/MessagePack/Converters/CharConverter.cs b/Shared/MessagePack/Converters/CharConverter.cs index 38d9956..9f145a8 100644 --- a/Shared/MessagePack/Converters/CharConverter.cs +++ b/Shared/MessagePack/Converters/CharConverter.cs @@ -1,33 +1,50 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if NANOFRAMEWORK_1_0 using System; +#endif using System.Diagnostics.CodeAnalysis; using nanoFramework.MessagePack.Stream; +using nanoFramework.MessagePack.Utility; namespace nanoFramework.MessagePack.Converters { internal class CharConverter : IConverter { - private static void Write(char value, IMessagePackWriter writer) - { - ConverterContext.GetConverter(typeof(ushort)).Write(BitConverter.ToUInt16(BitConverter.GetBytes(value), 0), writer); - } - - private static char Read(IMessagePackReader reader) - { - return BitConverter.ToChar(BitConverter.GetBytes((ushort)ConverterContext.GetConverter(typeof(ushort)).Read(reader)!), 0); - } - #nullable enable public void Write(object? value, [NotNull] IMessagePackWriter writer) { - Write((char)value!, writer); + if (value == null) + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentNullException(); +#else + throw new ArgumentNullException(nameof(value)); +#endif + } + if (value is char charValue) + { + ConverterContext.UshortConverter.Write(BitConverter.ToUInt16(BitConverter.GetBytes(charValue), 0), writer); + } + else + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentException(); +#else + throw new ArgumentException("Value must be of type char.", nameof(value)); +#endif + } } object? IConverter.Read([NotNull] IMessagePackReader reader) { - return Read(reader); + if (ConverterContext.UshortConverter.Read(reader) is ushort value) + { + return BitConverter.ToChar(BitConverter.GetBytes(value), 0); + } + + throw ExceptionUtility.BadTypeException(DataTypes.Null, DataTypes.UInt16); } } } diff --git a/Shared/MessagePack/Converters/DateTimeConverter.cs b/Shared/MessagePack/Converters/DateTimeConverter.cs index da21ba7..f6a2605 100644 --- a/Shared/MessagePack/Converters/DateTimeConverter.cs +++ b/Shared/MessagePack/Converters/DateTimeConverter.cs @@ -1,37 +1,53 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if NANOFRAMEWORK_1_0 using System; +#endif using System.Diagnostics.CodeAnalysis; using nanoFramework.MessagePack.Stream; +using nanoFramework.MessagePack.Utility; namespace nanoFramework.MessagePack.Converters { internal class DateTimeConverter : IConverter { - private static DateTime Read(IMessagePackReader reader) - { - var longValue = (long)ConverterContext.GetConverter(typeof(long)).Read(reader)!; - return DateTime.UnixEpoch.AddTicks(longValue); - } - - - private static void Write(DateTime value, IMessagePackWriter writer) - { - var longValue = value.Subtract(DateTime.UnixEpoch).Ticks; - - ConverterContext.GetConverter(typeof(long)).Write(longValue, writer); - } - #nullable enable public void Write(object? value, [NotNull] IMessagePackWriter writer) { - Write((DateTime)value!, writer); + if(value == null) + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentNullException(); +#else + throw new ArgumentNullException(nameof(value)); +#endif + } + + if (value is DateTime dateTimeValue) + { + var longValue = dateTimeValue.Subtract(DateTime.UnixEpoch).Ticks; + + ConverterContext.LongConverter.Write(longValue, writer); + } + else + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentException(); +#else + throw new ArgumentException("Value must be a non-null DateTime.", nameof(value)); +#endif + } } object? IConverter.Read([NotNull] IMessagePackReader reader) { - return Read(reader); + if (ConverterContext.LongConverter.Read(reader) is long value) + { + return DateTime.UnixEpoch.AddTicks(value); + } + + throw ExceptionUtility.BadTypeException(DataTypes.Null, DataTypes.Int64); } } } diff --git a/Shared/MessagePack/Converters/DoubleConverter.cs b/Shared/MessagePack/Converters/DoubleConverter.cs index 654a7b5..676d22f 100644 --- a/Shared/MessagePack/Converters/DoubleConverter.cs +++ b/Shared/MessagePack/Converters/DoubleConverter.cs @@ -13,55 +13,76 @@ namespace nanoFramework.MessagePack.Converters { internal class DoubleConverter : IConverter { - private static void Write(double value, IMessagePackWriter writer) +#nullable enable + public void Write(object? value, [NotNull] IMessagePackWriter writer) { - var binary = BitConverter.GetBytes(value); - byte[] bytes; - if (BitConverter.IsLittleEndian) + if(value == null) + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentNullException(); +#else + throw new ArgumentNullException(nameof(value)); +#endif + } + + if (value is double doubleValue) { - bytes = new[] + byte[] binary = BitConverter.GetBytes(doubleValue); + byte[] bytes; + if (BitConverter.IsLittleEndian) { - (byte) DataTypes.Double, - binary[7], - binary[6], - binary[5], - binary[4], - binary[3], - binary[2], - binary[1], - binary[0] - }; + bytes = new[] + { + (byte)DataTypes.Double, + binary[7], + binary[6], + binary[5], + binary[4], + binary[3], + binary[2], + binary[1], + binary[0] + }; + } + else + { + bytes = new[] + { + (byte)DataTypes.Double, + binary[0], + binary[1], + binary[2], + binary[3], + binary[4], + binary[5], + binary[6], + binary[7] + }; + } + + writer.Write(bytes); } else { - bytes = new[] - { - (byte) DataTypes.Double, - binary[0], - binary[1], - binary[2], - binary[3], - binary[4], - binary[5], - binary[6], - binary[7] - }; +#if NANOFRAMEWORK_1_0 + throw new ArgumentException(); +#else + throw new ArgumentException("Value must be of type double.", nameof(value)); +#endif } - - writer.Write(bytes); } - private static double Read(IMessagePackReader reader) + object? IConverter.Read([NotNull] IMessagePackReader reader) { - var type = reader.ReadDataType(); + DataTypes type = reader.ReadDataType(); if (type != DataTypes.Single && type != DataTypes.Double) { - //throw ExceptionUtility.BadTypeException(type, DataTypes.Single, DataTypes.Double); + ////throw ExceptionUtility.BadTypeException(type, DataTypes.Single, DataTypes.Double); - if (NumberConverterHelper.TryGetInt64(type, reader, out var result)) + if (NumberConverterHelper.TryGetInt64(type, reader, out long result)) { - return result; + return (double)result; } else { @@ -76,16 +97,5 @@ private static double Read(IMessagePackReader reader) return NumberConverterHelper.ReadDouble(reader); } - -#nullable enable - public void Write(object? value, [NotNull] IMessagePackWriter writer) - { - Write((double)value!, writer); - } - - object? IConverter.Read([NotNull] IMessagePackReader reader) - { - return Read(reader); - } } } diff --git a/Shared/MessagePack/Converters/FloatConverter.cs b/Shared/MessagePack/Converters/FloatConverter.cs index 2cff9cb..65c4602 100644 --- a/Shared/MessagePack/Converters/FloatConverter.cs +++ b/Shared/MessagePack/Converters/FloatConverter.cs @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if NANOFRAMEWORK_1_0 using System; +#endif using System.Diagnostics.CodeAnalysis; using nanoFramework.MessagePack.Extensions; using nanoFramework.MessagePack.Stream; @@ -11,64 +13,74 @@ namespace nanoFramework.MessagePack.Converters { internal class FloatConverter : IConverter { - private static void Write(float value, IMessagePackWriter writer) +#nullable enable + public void Write(object? value, [NotNull] IMessagePackWriter writer) { - var binary = BitConverter.GetBytes(value); - byte[] bytes; - if (BitConverter.IsLittleEndian) + if(value == null) + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentNullException(); +#else + throw new ArgumentNullException(nameof(value)); +#endif + } + + if (value is float floatValue) { - bytes = new[] + byte[] binary = BitConverter.GetBytes(floatValue); + byte[] bytes; + if (BitConverter.IsLittleEndian) { - (byte) DataTypes.Single, - binary[3], - binary[2], - binary[1], - binary[0] - }; + bytes = new[] + { + (byte)DataTypes.Single, + binary[3], + binary[2], + binary[1], + binary[0] + }; + } + else + { + bytes = new[] + { + (byte)DataTypes.Single, + binary[0], + binary[1], + binary[2], + binary[3] + }; + } + + writer.Write(bytes); } else { - bytes = new[] - { - (byte) DataTypes.Single, - binary[0], - binary[1], - binary[2], - binary[3] - }; +#if NANOFRAMEWORK_1_0 + throw new ArgumentException(); +#else + throw new ArgumentException("Value must be of type System.Single (float).", nameof(value)); +#endif } - - writer.Write(bytes); } - private static float Read(IMessagePackReader reader) + object? IConverter.Read([NotNull] IMessagePackReader reader) { - var type = reader.ReadDataType(); + DataTypes type = reader.ReadDataType(); if (type == DataTypes.Single) { return NumberConverterHelper.ReadFloat(reader); } - if (NumberConverterHelper.TryGetInt32(type, reader, out var result)) + if (NumberConverterHelper.TryGetInt32(type, reader, out int result)) { - return result; + return (float)result; } else { throw ExceptionUtility.BadTypeException(type, DataTypes.Single); } } - -#nullable enable - public void Write(object? value, [NotNull] IMessagePackWriter writer) - { - Write((float)value!, writer); - } - - object? IConverter.Read([NotNull] IMessagePackReader reader) - { - return Read(reader); - } } } diff --git a/Shared/MessagePack/Converters/GuidConverter.cs b/Shared/MessagePack/Converters/GuidConverter.cs index 08c82d3..64b2ba3 100644 --- a/Shared/MessagePack/Converters/GuidConverter.cs +++ b/Shared/MessagePack/Converters/GuidConverter.cs @@ -1,33 +1,50 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if NANOFRAMEWORK_1_0 using System; +#endif using System.Diagnostics.CodeAnalysis; using nanoFramework.MessagePack.Stream; +using nanoFramework.MessagePack.Utility; namespace nanoFramework.MessagePack.Converters { internal class GuidConverter : IConverter { - private static Guid Read([NotNull] IMessagePackReader reader) - { - return new Guid((byte[])ConverterContext.GetConverter(typeof(byte[])).Read(reader)!); - } - - private static void Write(Guid value, [NotNull] IMessagePackWriter writer) - { - ConverterContext.GetConverter(typeof(byte[])).Write(value.ToByteArray(), writer); - } - #nullable enable public void Write(object? value, [NotNull] IMessagePackWriter writer) { - Write((Guid)value!, writer); + if (value == null) + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentNullException(); +#else + throw new ArgumentNullException(nameof(value)); +#endif + } + if (value is Guid guidValue) + { + ConverterContext.BinaryConverter.Write(guidValue.ToByteArray(), writer); + } + else + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentException(); +#else + throw new ArgumentException("Value must be of type Guid.", nameof(value)); +#endif + } } object? IConverter.Read([NotNull] IMessagePackReader reader) { - return Read(reader); + if (ConverterContext.BinaryConverter.Read(reader) is byte[] byteArray) + { + return new Guid(byteArray); + } + + throw ExceptionUtility.BadTypeException(DataTypes.Null, DataTypes.Bin8); } } } diff --git a/Shared/MessagePack/Converters/IntConverter.cs b/Shared/MessagePack/Converters/IntConverter.cs index e12b673..6cf3696 100644 --- a/Shared/MessagePack/Converters/IntConverter.cs +++ b/Shared/MessagePack/Converters/IntConverter.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if NANOFRAMEWORK_1_0 +using System; +#endif using System.Diagnostics.CodeAnalysis; using nanoFramework.MessagePack.Extensions; using nanoFramework.MessagePack.Stream; @@ -10,34 +13,43 @@ namespace nanoFramework.MessagePack.Converters { internal class IntConverter : IConverter { - private static void Write(int value, IMessagePackWriter writer) +#nullable enable + public void Write(object? value, [NotNull] IMessagePackWriter writer) { - NumberConverterHelper.WriteInteger(value, writer); + if (value == null) + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentNullException(); +#else + throw new ArgumentNullException(nameof(value)); +#endif + } + if (value is int intValue) + { + NumberConverterHelper.WriteInteger(intValue, writer); + } + else + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentException(); +#else + throw new ArgumentException("Value must be of type Int32.", nameof(value)); +#endif + } } - private static int Read(IMessagePackReader reader) + object? IConverter.Read([NotNull] IMessagePackReader reader) { - var type = reader.ReadDataType(); + DataTypes type = reader.ReadDataType(); - if (NumberConverterHelper.TryGetInt32(type, reader, out var result)) + if (NumberConverterHelper.TryGetInt32(type, reader, out int result)) { return result; } else { - throw ExceptionUtility.IntDeserializationFailure(type); + throw ExceptionUtility.BadTypeException(type, DataTypes.PositiveFixNum, DataTypes.NegativeFixNum, DataTypes.UInt8, DataTypes.UInt16, DataTypes.Int8, DataTypes.Int16, DataTypes.Int32); } } - -#nullable enable - public void Write(object? value, [NotNull] IMessagePackWriter writer) - { - Write((int)value!, writer); - } - - object? IConverter.Read([NotNull] IMessagePackReader reader) - { - return Read(reader); - } } } diff --git a/Shared/MessagePack/Converters/LongConverter.cs b/Shared/MessagePack/Converters/LongConverter.cs index c7589a9..bf08308 100644 --- a/Shared/MessagePack/Converters/LongConverter.cs +++ b/Shared/MessagePack/Converters/LongConverter.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if NANOFRAMEWORK_1_0 +using System; +#endif using System.Diagnostics.CodeAnalysis; using nanoFramework.MessagePack.Extensions; using nanoFramework.MessagePack.Stream; @@ -10,34 +13,45 @@ namespace nanoFramework.MessagePack.Converters { internal class LongConverter : IConverter { - private static void Write(long value, IMessagePackWriter writer) +#nullable enable + public void Write(object? value, [NotNull] IMessagePackWriter writer) { - NumberConverterHelper.WriteInteger(value, writer); - } + if (value == null) + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentNullException(); +#else + throw new ArgumentNullException(nameof(value)); +#endif - private static long Read(IMessagePackReader reader) - { - var type = reader.ReadDataType(); + } - if (NumberConverterHelper.TryGetInt64(type, reader, out var result)) + if (value is long longValue) { - return result; + NumberConverterHelper.WriteInteger(longValue, writer); } else { - throw ExceptionUtility.IntDeserializationFailure(type); +#if NANOFRAMEWORK_1_0 + throw new ArgumentException(); +#else + throw new ArgumentException("Value must be of type long.", nameof(value)); +#endif } } -#nullable enable - public void Write(object? value, [NotNull] IMessagePackWriter writer) - { - Write((long)value!, writer); - } - object? IConverter.Read([NotNull] IMessagePackReader reader) { - return Read(reader); + DataTypes type = reader.ReadDataType(); + + if (NumberConverterHelper.TryGetInt64(type, reader, out long result)) + { + return result; + } + else + { + throw ExceptionUtility.BadTypeException(type, DataTypes.PositiveFixNum, DataTypes.NegativeFixNum, DataTypes.UInt8, DataTypes.UInt16, DataTypes.UInt32, DataTypes.Int8, DataTypes.Int16, DataTypes.Int32, DataTypes.Int64); + } } } } diff --git a/Shared/MessagePack/Converters/MapConverter.cs b/Shared/MessagePack/Converters/MapConverter.cs index 8aca161..91c25f7 100644 --- a/Shared/MessagePack/Converters/MapConverter.cs +++ b/Shared/MessagePack/Converters/MapConverter.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if NANOFRAMEWORK_1_0 +using System; +#endif using System.Collections; using System.Diagnostics.CodeAnalysis; using nanoFramework.MessagePack.Stream; @@ -9,7 +12,8 @@ namespace nanoFramework.MessagePack.Converters { internal class MapConverter : IConverter { - private static void Write(IDictionary value, IMessagePackWriter writer) +#nullable enable + internal static void Write(IDictionary? value, IMessagePackWriter writer) { if (value == null) { @@ -19,10 +23,21 @@ private static void Write(IDictionary value, IMessagePackWriter writer) writer.WriteMapHeader((uint)value.Count); + Type? preKeyType = null; + IConverter? keyConverter = null; + + Type? preValueType = null; + IConverter? valueConverter = null; + foreach (DictionaryEntry element in value) { - var keyType = element.Key.GetType(); - var keyConverter = ConverterContext.GetConverter(keyType); + Type keyType = element.Key.GetType(); + if (keyType != preKeyType) + { + keyConverter = ConverterContext.GetConverter(keyType); + preKeyType = keyType; + } + if (keyConverter == null) { ConverterContext.SerializeObject(keyType, element.Key, writer); @@ -39,7 +54,12 @@ private static void Write(IDictionary value, IMessagePackWriter writer) else { var valueType = element.Value.GetType(); - var valueConverter = ConverterContext.GetConverter(valueType); + if (valueType != preValueType) + { + valueConverter = ConverterContext.GetConverter(valueType); + preValueType = valueType; + } + if (valueConverter == null) { ConverterContext.SerializeObject(valueType, element.Value, writer); @@ -52,23 +72,36 @@ private static void Write(IDictionary value, IMessagePackWriter writer) } } -#nullable enable internal static Hashtable? Read(IMessagePackReader reader) { - var length = reader.ReadMapLength(); - return ((long)length) > -1 ? ReadMap(reader, length) : null; + int length = (int)reader.ReadMapLength(); + return length > -1 ? ReadMap(reader, length) : null; } - internal static Hashtable ReadMap(IMessagePackReader reader, uint length) + internal static Hashtable ReadMap(IMessagePackReader reader, int length) { - var map = new Hashtable(); + if (length < 0) + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentOutOfRangeException(); +#else + throw new ArgumentOutOfRangeException(nameof(length), "Map length cannot be negative."); +#endif + } + + var map = new Hashtable(length); - for (var i = 0; i < length; i++) + while (length-- > 0) { - var key = ConverterContext.GetObjectByDataType(reader); + var key = ConverterContext.GetObjectByDataType(reader) ?? +#if NANOFRAMEWORK_1_0 + throw new InvalidOperationException(); +#else + throw new InvalidOperationException("Map key cannot be null."); +#endif var value = ConverterContext.GetObjectByDataType(reader); - map[key!] = value; + map[key] = value; } return map; @@ -76,7 +109,7 @@ internal static Hashtable ReadMap(IMessagePackReader reader, uint length) public void Write(object? value, [NotNull] IMessagePackWriter writer) { - Write((Hashtable)value!, writer); + Write((Hashtable?)value, writer); } object? IConverter.Read([NotNull] IMessagePackReader reader) diff --git a/Shared/MessagePack/Converters/SbyteConverter.cs b/Shared/MessagePack/Converters/SbyteConverter.cs index 8998f59..7956f3b 100644 --- a/Shared/MessagePack/Converters/SbyteConverter.cs +++ b/Shared/MessagePack/Converters/SbyteConverter.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if NANOFRAMEWORK_1_0 +using System; +#endif using System.Diagnostics.CodeAnalysis; using nanoFramework.MessagePack.Extensions; using nanoFramework.MessagePack.Stream; @@ -10,14 +13,35 @@ namespace nanoFramework.MessagePack.Converters { internal class SbyteConverter : IConverter { - private static void Write(sbyte value, IMessagePackWriter writer) +#nullable enable + public void Write(object? value, [NotNull] IMessagePackWriter writer) { - NumberConverterHelper.WriteInteger(value, writer); + if (value is null) + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentNullException(); +#else + throw new ArgumentNullException(nameof(value)); +#endif + } + + if (value is sbyte sbyteValue) + { + NumberConverterHelper.WriteInteger(sbyteValue, writer); + } + else + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentException(); +#else + throw new ArgumentException("Value must be of type sbyte.", nameof(value)); +#endif + } } - private static sbyte Read(IMessagePackReader reader) + object IConverter.Read([NotNull] IMessagePackReader reader) { - var type = reader.ReadDataType(); + DataTypes type = reader.ReadDataType(); if (NumberConverterHelper.TryGetFixPositiveNumber(type, out byte temp)) { @@ -34,18 +58,7 @@ private static sbyte Read(IMessagePackReader reader) return NumberConverterHelper.ReadInt8(reader); } - throw ExceptionUtility.IntDeserializationFailure(type); - } - -#nullable enable - public void Write(object? value, [NotNull] IMessagePackWriter writer) - { - Write((sbyte)value!, writer); - } - - object IConverter.Read([NotNull] IMessagePackReader reader) - { - return Read(reader); + throw ExceptionUtility.BadTypeException(type, DataTypes.PositiveFixNum, DataTypes.NegativeFixNum, DataTypes.Int8); } } } diff --git a/Shared/MessagePack/Converters/ShortConverter.cs b/Shared/MessagePack/Converters/ShortConverter.cs index 470df9b..85fbc33 100644 --- a/Shared/MessagePack/Converters/ShortConverter.cs +++ b/Shared/MessagePack/Converters/ShortConverter.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if NANOFRAMEWORK_1_0 +using System; +#endif using System.Diagnostics.CodeAnalysis; using nanoFramework.MessagePack.Extensions; using nanoFramework.MessagePack.Stream; @@ -10,59 +13,67 @@ namespace nanoFramework.MessagePack.Converters { internal class ShortConverter : IConverter { - private static void Write(short value, IMessagePackWriter writer) +#nullable enable + public void Write(object? value, [NotNull] IMessagePackWriter writer) { - NumberConverterHelper.WriteInteger(value, writer); + if (value == null) + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentNullException(); +#else + throw new ArgumentNullException(nameof(value)); +#endif + } + if (value is short shortValue) + { + NumberConverterHelper.WriteInteger(shortValue, writer); + } + else + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentException(); +#else + throw new ArgumentException("Value must be of type short.", nameof(value)); +#endif + } } - private static short Read(IMessagePackReader reader) + object IConverter.Read([NotNull] IMessagePackReader reader) { - var type = reader.ReadDataType(); + DataTypes type = reader.ReadDataType(); if (NumberConverterHelper.TryGetFixPositiveNumber(type, out byte temp)) { - return temp; + return (short)temp; } if (NumberConverterHelper.TryGetNegativeNumber(type, out sbyte tempInt8)) { - return tempInt8; + return (short)tempInt8; } switch (type) { case DataTypes.UInt8: - return NumberConverterHelper.ReadUInt8(reader); + return reader.ReadByte(); case DataTypes.UInt16: - var ushortValue = NumberConverterHelper.ReadUInt16(reader); + ushort ushortValue = NumberConverterHelper.ReadUInt16(reader); if (ushortValue <= short.MaxValue) { return (short)ushortValue; } - throw ExceptionUtility.IntDeserializationFailure(type); + throw ExceptionUtility.BadTypeException(type, DataTypes.UInt16); case DataTypes.Int8: - return NumberConverterHelper.ReadInt8(reader); + return (short)NumberConverterHelper.ReadInt8(reader); case DataTypes.Int16: return NumberConverterHelper.ReadInt16(reader); - default: - throw ExceptionUtility.IntDeserializationFailure(type); + throw ExceptionUtility.BadTypeException(type, DataTypes.PositiveFixNum, DataTypes.NegativeFixNum, DataTypes.UInt8, DataTypes.Int8, DataTypes.Int16); } } - -#nullable enable - public void Write(object? value, [NotNull] IMessagePackWriter writer) - { - Write((short)value!, writer); - } - - object IConverter.Read([NotNull] IMessagePackReader reader) - { - return Read(reader); - } } } diff --git a/Shared/MessagePack/Converters/SimpleArrayConverter.cs b/Shared/MessagePack/Converters/SimpleArrayConverter.cs index 9df7bf5..3fb84a8 100644 --- a/Shared/MessagePack/Converters/SimpleArrayConverter.cs +++ b/Shared/MessagePack/Converters/SimpleArrayConverter.cs @@ -1,7 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. - +#if NANOFRAMEWORK_1_0 using System; +#endif using System.Collections; using System.Diagnostics.CodeAnalysis; using nanoFramework.MessagePack.Stream; @@ -10,27 +11,44 @@ namespace nanoFramework.MessagePack.Converters { /// - /// Simple array converter + /// Simple array converter. /// public class SimpleArrayConverter : IConverter { +#nullable enable private readonly Type _elementType; /// - /// Simple array converter + /// Initializes a new instance of the class. /// - /// Type of array element + /// Type of array element. public SimpleArrayConverter(Type elementType) { _elementType = elementType; } /// - /// Write array in to MessagePack stream + /// Write array in to MessagePack stream. + /// + /// Array to by write. + /// MessagePack stream for written. + public void Write(Array? value, IMessagePackWriter writer) + { + Write(value, _elementType, writer); + } + + /// + /// Read array from MessagePack stream. /// - /// Array to by write - /// MessagePack stream for written - public void Write(Array value, IMessagePackWriter writer) + /// MessagePack stream for reading. + /// Readied array. + public Array? Read(IMessagePackReader reader) + { + var length = (int)reader.ReadArrayLength(); + return length > -1 ? ReadArray(reader, length, _elementType ?? throw ExceptionUtility.ConverterNotFound(typeof(object))) : null; + } + + internal static void Write(Array? value, Type? elementType, IMessagePackWriter writer) { if (value == null) { @@ -38,61 +56,79 @@ public void Write(Array value, IMessagePackWriter writer) return; } - var converter = ConverterContext.GetConverter(_elementType) ?? throw ExceptionUtility.NoConverterForCollectionElement(_elementType, "item"); - writer.WriteArrayHeader((uint)value.Length); - - foreach (var element in value) + if (value.Length > 0) { - converter.Write(element, writer); + if (elementType == null) + { + Type arrayType = value.GetType(); + elementType = arrayType.GetElementType() ?? throw ExceptionUtility.ConverterNotFound(typeof(object)); + } + + var elementConverter = ConverterContext.GetConverter(elementType); + if (elementConverter != null) + { + foreach (var element in value) + { + elementConverter.Write(element, writer); + } + } + else + { + foreach (var element in value) + { + ConverterContext.SerializeObject(elementType, element, writer); + } + } } } - /// - /// Read array from MessagePack stream - /// - /// MessagePack stream for reading - /// Readied array -#nullable enable - public Array? Read(IMessagePackReader reader) + internal static IList? Read(IMessagePackReader reader, Type arrayType) { var length = (int)reader.ReadArrayLength(); - - return length > -1 ? ReadArray(reader, length) : null; + return length > 0 ? ReadArray(reader, length, arrayType.GetElementType() ?? throw ExceptionUtility.ConverterNotFound(typeof(object))) : null; } - private Array ReadArray(IMessagePackReader reader, int length) + private static Array ReadArray(IMessagePackReader reader, int length, Type elementType) { - var converter = ConverterContext.GetConverter(_elementType); - - var result = (IList)Array.CreateInstance(_elementType, length); - - if (converter != null) + var targetArray = (IList)Array.CreateInstance(elementType, length); + if (elementType.IsArray) { for (var i = 0; i < length; i++) { - result[i] = converter.Read(reader)!; + targetArray[i] = Read(reader, elementType); } } else { - for (var i = 0; i < length; i++) + var converter = ConverterContext.GetConverter(elementType); + if (converter != null) + { + for (var i = 0; i < length; i++) + { + targetArray[i] = converter.Read(reader); + } + } + else { - result[i] = ConverterContext.DeserializeObject(_elementType, reader); + for (var i = 0; i < length; i++) + { + targetArray[i] = ConverterContext.DeserializeObject(elementType, reader); + } } } - return (Array)result; + return (Array)targetArray; } void IConverter.Write(object? value, [NotNull] IMessagePackWriter writer) { - Write((Array)value!, writer); + Write((Array?)value, writer); } object? IConverter.Read([NotNull] IMessagePackReader reader) { - return Read(reader)!; + return Read(reader); } } } diff --git a/Shared/MessagePack/Converters/StringConverter.cs b/Shared/MessagePack/Converters/StringConverter.cs index 01cef5b..8bb7610 100644 --- a/Shared/MessagePack/Converters/StringConverter.cs +++ b/Shared/MessagePack/Converters/StringConverter.cs @@ -14,7 +14,8 @@ internal class StringConverter : IConverter { private static readonly Encoding Utf8 = new UTF8Encoding(); - private static void Write(string value, IMessagePackWriter writer) +#nullable enable + private static void Write(string? value, IMessagePackWriter writer) { if (value == null) { @@ -24,12 +25,12 @@ private static void Write(string value, IMessagePackWriter writer) { var data = Utf8.GetBytes(value); - WriteStringHeaderAndLength(writer, data.Length); + WriteStringHeaderAndLength(writer, (uint)data.Length); writer.Write(data); } } -#nullable enable + private static string? Read(IMessagePackReader reader) { DataTypes type = reader.ReadDataType(); @@ -39,16 +40,16 @@ private static void Write(string value, IMessagePackWriter writer) case DataTypes.Null: return null; case DataTypes.Str8: - return ReadString(reader, NumberConverterHelper.ReadUInt8(reader)); + return ReadString(reader, reader.ReadByte()); case DataTypes.Str16: return ReadString(reader, NumberConverterHelper.ReadUInt16(reader)); case DataTypes.Str32: return ReadString(reader, NumberConverterHelper.ReadUInt32(reader)); } - if (TryGetFixStrLength(type, out uint length)) + if (type.GetHighBits(3) == DataTypes.FixStr.GetHighBits(3)) { - return ReadString(reader, length); + return ReadString(reader, type - DataTypes.FixStr); } throw ExceptionUtility.BadTypeException(type, DataTypes.FixStr, DataTypes.Str8, DataTypes.Str16, DataTypes.Str32); @@ -61,13 +62,7 @@ internal static string ReadString(IMessagePackReader reader, uint length) return Utf8.GetString(arraySegment.SourceBuffer, (int)arraySegment.SourceOffset + arraySegment.Position, (int)arraySegment.Length); } - private static bool TryGetFixStrLength(DataTypes type, out uint length) - { - length = type - DataTypes.FixStr; - return type.GetHighBits(3) == DataTypes.FixStr.GetHighBits(3); - } - - private static void WriteStringHeaderAndLength(IMessagePackWriter writer, int length) + private static void WriteStringHeaderAndLength(IMessagePackWriter writer, uint length) { if (length <= 31) { @@ -78,7 +73,7 @@ private static void WriteStringHeaderAndLength(IMessagePackWriter writer, int le if (length <= byte.MaxValue) { writer.Write(DataTypes.Str8); - ((byte)length).WriteByteValue(writer); + writer.Write((byte)length); } else if (length <= ushort.MaxValue) { @@ -88,14 +83,13 @@ private static void WriteStringHeaderAndLength(IMessagePackWriter writer, int le else { writer.Write(DataTypes.Str32); - NumberConverterHelper.WriteUIntValue((uint)length, writer); + NumberConverterHelper.WriteUIntValue(length, writer); } } -#nullable enable public void Write(object? value, [NotNull] IMessagePackWriter writer) { - Write((string)value!, writer); + Write((string?)value, writer); } object? IConverter.Read([NotNull] IMessagePackReader reader) diff --git a/Shared/MessagePack/Converters/TimeSpanConverter.cs b/Shared/MessagePack/Converters/TimeSpanConverter.cs index 505befa..ab2bea0 100644 --- a/Shared/MessagePack/Converters/TimeSpanConverter.cs +++ b/Shared/MessagePack/Converters/TimeSpanConverter.cs @@ -1,35 +1,50 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if NANOFRAMEWORK_1_0 using System; +#endif using System.Diagnostics.CodeAnalysis; using nanoFramework.MessagePack.Stream; +using nanoFramework.MessagePack.Utility; namespace nanoFramework.MessagePack.Converters { internal class TimeSpanConverter : IConverter { - private static void Write(TimeSpan value, IMessagePackWriter writer) - { - ConverterContext.GetConverter(typeof(long)).Write(value.Ticks, writer); - } - - private static TimeSpan Read(IMessagePackReader reader) - { - var longValue = (long)ConverterContext.GetConverter(typeof(long)).Read(reader)!; - - return TimeSpan.FromTicks(longValue); - } - #nullable enable public void Write(object? value, [NotNull] IMessagePackWriter writer) { - Write((TimeSpan)value!, writer); + if (value == null) + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentNullException(); +#else + throw new ArgumentNullException(nameof(value)); +#endif + } + if (value is TimeSpan timeSpanValue) + { + ConverterContext.LongConverter.Write(timeSpanValue.Ticks, writer); + } + else + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentException(); +#else + throw new ArgumentException("Value must be of type TimeSpan.", nameof(value)); +#endif + } } object? IConverter.Read([NotNull] IMessagePackReader reader) { - return Read(reader); + if (ConverterContext.LongConverter.Read(reader) is long longValue) + { + return TimeSpan.FromTicks(longValue); + } + + throw ExceptionUtility.BadTypeException(DataTypes.Null, DataTypes.Int64); } } } diff --git a/Shared/MessagePack/Converters/UintConverter.cs b/Shared/MessagePack/Converters/UintConverter.cs index a969fce..73d4126 100644 --- a/Shared/MessagePack/Converters/UintConverter.cs +++ b/Shared/MessagePack/Converters/UintConverter.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if NANOFRAMEWORK_1_0 +using System; +#endif using System.Diagnostics.CodeAnalysis; using nanoFramework.MessagePack.Extensions; using nanoFramework.MessagePack.Stream; @@ -10,18 +13,39 @@ namespace nanoFramework.MessagePack.Converters { internal class UintConverter : IConverter { - private static void Write(uint value, IMessagePackWriter writer) +#nullable enable + public void Write(object? value, [NotNull] IMessagePackWriter writer) { - NumberConverterHelper.WriteNonNegativeInteger(value, writer); + if(value == null) + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentNullException(); +#else + throw new ArgumentNullException(nameof(value)); +#endif + } + + if (value is uint uintValue) + { + NumberConverterHelper.WriteNonNegativeInteger(uintValue, writer); + } + else + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentException(); +#else + throw new ArgumentException("Value must be of type uint.", nameof(value)); +#endif + } } - private static uint Read(IMessagePackReader reader) + object? IConverter.Read([NotNull] IMessagePackReader reader) { - var type = reader.ReadDataType(); + DataTypes type = reader.ReadDataType(); if (NumberConverterHelper.TryGetFixPositiveNumber(type, out byte temp)) { - return temp; + return (uint)temp; } if (NumberConverterHelper.TryGetNegativeNumber(type, out sbyte tempInt8)) @@ -31,25 +55,14 @@ private static uint Read(IMessagePackReader reader) return type switch { - DataTypes.UInt8 => NumberConverterHelper.ReadUInt8(reader), - DataTypes.UInt16 => NumberConverterHelper.ReadUInt16(reader), + DataTypes.UInt8 => (uint)reader.ReadByte(), + DataTypes.UInt16 => (uint)NumberConverterHelper.ReadUInt16(reader), DataTypes.UInt32 => NumberConverterHelper.ReadUInt32(reader), DataTypes.Int8 => (uint)NumberConverterHelper.ReadInt8(reader), DataTypes.Int16 => (uint)NumberConverterHelper.ReadInt16(reader), DataTypes.Int32 => (uint)NumberConverterHelper.ReadInt32(reader), - _ => throw ExceptionUtility.IntDeserializationFailure(type), + _ => throw ExceptionUtility.BadTypeException(type, DataTypes.PositiveFixNum, DataTypes.NegativeFixNum, DataTypes.UInt8, DataTypes.UInt16, DataTypes.Int8, DataTypes.Int16, DataTypes.Int32, DataTypes.UInt32) }; } - -#nullable enable - public void Write(object? value, [NotNull] IMessagePackWriter writer) - { - Write((uint)value!, writer); - } - - object? IConverter.Read([NotNull] IMessagePackReader reader) - { - return Read(reader); - } } } diff --git a/Shared/MessagePack/Converters/UlongConverter.cs b/Shared/MessagePack/Converters/UlongConverter.cs index 2791fec..42e7054 100644 --- a/Shared/MessagePack/Converters/UlongConverter.cs +++ b/Shared/MessagePack/Converters/UlongConverter.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if NANOFRAMEWORK_1_0 +using System; +#endif using System.Diagnostics.CodeAnalysis; using nanoFramework.MessagePack.Extensions; using nanoFramework.MessagePack.Stream; @@ -10,18 +13,38 @@ namespace nanoFramework.MessagePack.Converters { internal class UlongConverter : IConverter { - private static void Write(ulong value, IMessagePackWriter writer) +#nullable enable + public void Write(object? value, [NotNull] IMessagePackWriter writer) { - NumberConverterHelper.WriteNonNegativeInteger(value, writer); + if(value == null) + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentNullException(); +#else + throw new ArgumentNullException(nameof(value)); +#endif + } + if (value is ulong ulongValue) + { + NumberConverterHelper.WriteNonNegativeInteger(ulongValue, writer); + } + else + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentException(); +#else + throw new ArgumentException("Value must be of type ulong.", nameof(value)); +#endif + } } - private static ulong Read(IMessagePackReader reader) + object? IConverter.Read([NotNull] IMessagePackReader reader) { - var type = reader.ReadDataType(); + DataTypes type = reader.ReadDataType(); if (NumberConverterHelper.TryGetFixPositiveNumber(type, out byte temp)) { - return temp; + return (ulong)temp; } if (NumberConverterHelper.TryGetNegativeNumber(type, out sbyte tempInt8)) @@ -31,27 +54,16 @@ private static ulong Read(IMessagePackReader reader) return type switch { - DataTypes.UInt8 => NumberConverterHelper.ReadUInt8(reader), - DataTypes.UInt16 => NumberConverterHelper.ReadUInt16(reader), - DataTypes.UInt32 => NumberConverterHelper.ReadUInt32(reader), + DataTypes.UInt8 => (ulong)reader.ReadByte(), + DataTypes.UInt16 => (ulong)NumberConverterHelper.ReadUInt16(reader), + DataTypes.UInt32 => (ulong)NumberConverterHelper.ReadUInt32(reader), DataTypes.UInt64 => NumberConverterHelper.ReadUInt64(reader), DataTypes.Int8 => (ulong)NumberConverterHelper.ReadInt8(reader), DataTypes.Int16 => (ulong)NumberConverterHelper.ReadInt16(reader), DataTypes.Int32 => (ulong)NumberConverterHelper.ReadInt32(reader), DataTypes.Int64 => (ulong)reader.ReadInt64(), - _ => throw ExceptionUtility.IntDeserializationFailure(type), + _ => throw ExceptionUtility.BadTypeException(type, DataTypes.PositiveFixNum, DataTypes.NegativeFixNum, DataTypes.UInt8, DataTypes.UInt16, DataTypes.UInt32, DataTypes.Int8, DataTypes.Int16, DataTypes.Int32, DataTypes.Int64, DataTypes.UInt64) }; } - -#nullable enable - public void Write(object? value, [NotNull] IMessagePackWriter writer) - { - Write((ulong)value!, writer); - } - - object? IConverter.Read([NotNull] IMessagePackReader reader) - { - return Read(reader); - } } } diff --git a/Shared/MessagePack/Converters/UshortConverter.cs b/Shared/MessagePack/Converters/UshortConverter.cs index 6f1f92d..dcaaf57 100644 --- a/Shared/MessagePack/Converters/UshortConverter.cs +++ b/Shared/MessagePack/Converters/UshortConverter.cs @@ -1,6 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if NANOFRAMEWORK_1_0 +using System; +#endif using System.Diagnostics.CodeAnalysis; using nanoFramework.MessagePack.Extensions; using nanoFramework.MessagePack.Stream; @@ -10,18 +13,38 @@ namespace nanoFramework.MessagePack.Converters { internal class UshortConverter : IConverter { - private static void Write(ushort value, IMessagePackWriter writer) +#nullable enable + public void Write(object? value, [NotNull] IMessagePackWriter writer) { - NumberConverterHelper.WriteNonNegativeInteger(value, writer); + if(value == null) + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentNullException(); +#else + throw new ArgumentNullException(nameof(value)); +#endif + } + if (value is ushort ushortValue) + { + NumberConverterHelper.WriteNonNegativeInteger(ushortValue, writer); + } + else + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentException(); +#else + throw new ArgumentException($"The type of {nameof(value)} is not ushort."); +#endif + } } - private static ushort Read(IMessagePackReader reader) + object? IConverter.Read([NotNull] IMessagePackReader reader) { - var type = reader.ReadDataType(); + DataTypes type = reader.ReadDataType(); if (NumberConverterHelper.TryGetFixPositiveNumber(type, out byte temp)) { - return temp; + return (ushort)temp; } if (NumberConverterHelper.TryGetNegativeNumber(type, out sbyte tempInt8)) @@ -31,23 +54,12 @@ private static ushort Read(IMessagePackReader reader) return type switch { - DataTypes.UInt8 => NumberConverterHelper.ReadUInt8(reader), + DataTypes.UInt8 => (ushort)reader.ReadByte(), DataTypes.UInt16 => NumberConverterHelper.ReadUInt16(reader), DataTypes.Int8 => (ushort)NumberConverterHelper.ReadInt8(reader), DataTypes.Int16 => (ushort)NumberConverterHelper.ReadInt16(reader), - _ => throw ExceptionUtility.IntDeserializationFailure(type), + _ => throw ExceptionUtility.BadTypeException(type, DataTypes.PositiveFixNum, DataTypes.NegativeFixNum, DataTypes.UInt8, DataTypes.Int8, DataTypes.Int16, DataTypes.UInt16) }; } - -#nullable enable - public void Write(object? value, [NotNull] IMessagePackWriter writer) - { - Write((ushort)value!, writer); - } - - object? IConverter.Read([NotNull] IMessagePackReader reader) - { - return Read(reader); - } } } diff --git a/Shared/MessagePack/Dto/ArraySegment.cs b/Shared/MessagePack/Dto/ArraySegment.cs index f3912dc..43a66cb 100644 --- a/Shared/MessagePack/Dto/ArraySegment.cs +++ b/Shared/MessagePack/Dto/ArraySegment.cs @@ -145,7 +145,7 @@ private byte[] ToArray() { var data = new byte[_length]; - System.Array.Copy(_buffer, (int)_offset, data, 0, (int)_length); + Array.Copy(_buffer, (int)_offset, data, 0, (int)_length); return data; } diff --git a/Shared/MessagePack/Dto/MemberMapping.cs b/Shared/MessagePack/Dto/MemberMapping.cs index fe0dfa1..b0eebf3 100644 --- a/Shared/MessagePack/Dto/MemberMapping.cs +++ b/Shared/MessagePack/Dto/MemberMapping.cs @@ -1,119 +1,71 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if NANOFRAMEWORK_1_0 using System; +#endif using System.Reflection; namespace nanoFramework.MessagePack.Dto { internal class MemberMapping { -#if NANOFRAMEWORK_1_0 - internal const string GET_ = "get_"; - internal const string SET_ = "set_"; -#endif - #nullable enable - public MemberMapping(FieldInfo field) => Field = field; -#if NANOFRAMEWORK_1_0 - public MemberMapping(MethodInfo property) => Property = property; - private MethodInfo? Property { get; set; } - public string? Name => Field?.Name ?? Property?.Name.Substring(4); - public Type? DeclaringType => Field?.DeclaringType ?? Property?.DeclaringType; - -#else - public MemberMapping(PropertyInfo property) => Property = property; - private PropertyInfo? Property { get; set; } - public string? Name => Field?.Name ?? Property?.Name; - public Type? DeclaringType => Field?.DeclaringType ?? Property?.DeclaringType; -#endif - public string? OriginalName => Field?.Name ?? Property?.Name; - private FieldInfo? Field { get; set; } + private readonly FieldInfo? _field; - public Type? GetMemberType() + private readonly PropertyInfo? _property; + + public MemberMapping(PropertyInfo property) { - if (Field != null) - { - return Field.FieldType; - } - else -#if NANOFRAMEWORK_1_0 - if (Property != null) - { - return GetPropertyType(Property); - } -#else - if (Property != null) - { - return Property.PropertyType; - } -#endif + _property = property; + Name = property.Name; + MemberType = property.PropertyType; + } - return null; + public MemberMapping(FieldInfo field) + { + _field = field; + Name = field.Name; + MemberType = field.FieldType; } - public bool TryGetValue(object obj, out object value) + public string Name { get; } + + public Type MemberType { get; } + + public bool TryGetValue(object obj, out object? value) { - if (Field != null) + if (_field != null) { - value = Field.GetValue(obj)!; + value = _field.GetValue(obj); return true; } - if (Property != null) + if (_property != null) { -#if NANOFRAMEWORK_1_0 - if (Property.Name.StartsWith(GET_)) - { - value = Property.Invoke(obj, null); - return true; - } -#else - value = Property.GetValue(obj)!; + value = _property.GetValue(obj, null); return true; -#endif } - value = null!; + + value = null; return false; } - +#if DEBUG public override string ToString() { - return $"{Field?.Name}{Property?.Name}"; + return $"{_field?.Name ?? string.Empty}{_property?.Name ?? string.Empty}"; } - internal void SetValue(object current, object val) - { - if (Field != null) - { - Field.SetValue(current, val); - } - else -#if NANOFRAMEWORK_1_0 - if (Property != null && Property.Name.StartsWith(SET_)) - { - Property.Invoke(current, new object[] { val }); - } -#else - if (Property != null) - { - Property.SetValue(current, val); - } #endif - } -#if NANOFRAMEWORK_1_0 - internal static Type GetPropertyType(MethodInfo methodInfo) + internal void SetValue(object current, object? val) { - if (methodInfo.Name.StartsWith(GET_)) + if (_field != null) { - return methodInfo.ReturnType; + _field.SetValue(current, val); } - else if (methodInfo.Name.StartsWith(SET_)) + else { - return methodInfo.GetParameters()[0].ParameterType; + _property?.SetValue(current, val, null); } - - throw new Exception($"Method {methodInfo.Name} is not Property set or get method."); } -#endif } } diff --git a/Shared/MessagePack/Dto/MemberPropertyInfo.cs b/Shared/MessagePack/Dto/MemberPropertyInfo.cs new file mode 100644 index 0000000..8b5538e --- /dev/null +++ b/Shared/MessagePack/Dto/MemberPropertyInfo.cs @@ -0,0 +1,174 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if NANOFRAMEWORK_1_0 +using System; +using System.Collections; +using System.Reflection; + +namespace nanoFramework.MessagePack.Dto +{ + internal class MemberPropertyInfo : PropertyInfo + { + internal const string GET_ = "get_"; + internal const string SET_ = "set_"; +#nullable enable + private readonly MethodInfo? _getMethodInfo; + private readonly MethodInfo? _setMethodInfo; + + private MemberPropertyInfo(MethodInfo? getMethod, MethodInfo? setMethod) + { + MethodInfo? mi; + + if (getMethod != null) + { + PropertyType = getMethod.ReturnType; + mi = getMethod; + } + else if (setMethod != null) + { + ParameterInfo[] parametersInfo = setMethod.GetParameters(); + if (parametersInfo.Length == 1) + { + PropertyType = parametersInfo[0].ParameterType; + mi = setMethod; + } + else + { + throw new InvalidOperationException(); + } + } + else + { + throw new ArgumentNullException(); + } + + _getMethodInfo = getMethod; + _setMethodInfo = setMethod; + + DeclaringType = mi.DeclaringType; + if(mi.Name.Length > 4) + { + Name = mi.Name.Substring(4); + } + else + { + throw new InvalidOperationException(); + } + } + + public override Type PropertyType { get; } + + public override MemberTypes MemberType => MemberTypes.Property; + + public override string Name { get; } + + public override Type DeclaringType { get; } + + private static Hashtable GetPropertiesMethods(Type type, BindingFlags bindingAttr) + { + var propertyHashtable = new Hashtable(); + MethodInfo[] methods = type.GetMethods(bindingAttr); + + foreach (MethodInfo method in methods) + { + if (ShouldSerializeMethod(method)) + { + string propertyName = method.Name.Substring(4); + var methodInfos = (MethodInfo?[])propertyHashtable[propertyName]; + if (methodInfos == null) + { + methodInfos = new MethodInfo?[2]; + propertyHashtable[propertyName] = methodInfos; + } + + methodInfos[method.Name.StartsWith(GET_) ? 0 : 1] = method; + } + } + return propertyHashtable; + } + + private static bool ShouldSerializeMethod(MethodInfo method) + { + // We care only about property getters when serializing and setter deserializing + if (!method.Name.StartsWith(GET_) && !method.Name.StartsWith(SET_)) + { + return false; + } + + // Ignore abstract and virtual objects + if (method.IsAbstract) + { + return false; + } + + // Ignore static methods + if (method.IsStatic) + { + return false; + } + + // Ignore delegates and MethodInfos + if ((method.ReturnType == typeof(Delegate)) || + (method.ReturnType == typeof(MulticastDelegate)) || + (method.ReturnType == typeof(MethodInfo))) + { + return false; + } + + // Ditto for DeclaringType + if ((method.DeclaringType == typeof(Delegate)) || + (method.DeclaringType == typeof(MulticastDelegate))) + { + return false; + } + + return true; + } + + public static MemberPropertyInfo[] GetProperties(Type type, BindingFlags bindingAttr) + { + var propertyHashtable = GetPropertiesMethods(type, bindingAttr); + + MemberPropertyInfo[] result = new MemberPropertyInfo[propertyHashtable.Count]; + + int index = 0; + foreach (DictionaryEntry entry in propertyHashtable) + { + if (entry.Value is MethodInfo?[] methodInfos) + { + result[index] = new MemberPropertyInfo(methodInfos[0], methodInfos[1]); + index++; + } + else + { + throw new ArgumentException(); + } + } + + return result; + } + + public override object[] GetCustomAttributes(bool inherit) + { + object[] getAttrs = _getMethodInfo?.GetCustomAttributes(inherit) ?? new object[0]; + object[] setAttrs = _setMethodInfo?.GetCustomAttributes(inherit) ?? new object[0]; + + object[] resultAttrs = new object[getAttrs.Length + setAttrs.Length]; + Array.Copy(getAttrs, 0, resultAttrs, 0, getAttrs.Length); + Array.Copy(setAttrs, 0, resultAttrs, getAttrs.Length, setAttrs.Length); + return resultAttrs; + } + + public override object? GetValue(object obj, object[] parameters) + { + return _getMethodInfo?.Invoke(obj, null); + } + + public override void SetValue(object obj, object? value, object[] index) + { + _setMethodInfo?.Invoke(obj, new object?[] { value }); + } + } +} +#endif diff --git a/Shared/MessagePack/Dto/TypeValueDictionary.cs b/Shared/MessagePack/Dto/TypeValueDictionary.cs new file mode 100644 index 0000000..878520f --- /dev/null +++ b/Shared/MessagePack/Dto/TypeValueDictionary.cs @@ -0,0 +1,198 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if NANOFRAMEWORK_1_0 +using System; +#endif +using System.Collections; + +namespace nanoFramework.MessagePack.Dto +{ + /// + /// Represents a dictionary class for storing and values. + /// + public class TypeValueDictionary : ICollection + { + private readonly ArrayList _dictionaryEntries = new ArrayList(); + +#nullable enable + /// + /// Sets or Gets the element at the given key. + /// + /// Key value. + /// value or . + public object? this[Type key] + { + get + { +#if NANOFRAMEWORK_1_0 + return GetElement(key)?.Value; +#else + return GetElement(key, out _)?.Value; +#endif + } + + set + { + lock (_dictionaryEntries.SyncRoot) + { +#if NANOFRAMEWORK_1_0 + DictionaryEntry? element = GetElement(key); +#else + DictionaryEntry? element = GetElement(key, out int index); +#endif + if (element != null) + { +#if NANOFRAMEWORK_1_0 + element.Value = value; +#else + _dictionaryEntries[index] = new DictionaryEntry(key, value); +#endif + } + else + { + _dictionaryEntries.Add(new DictionaryEntry(key, value)); + } + } + } + } + + int ICollection.Count => _dictionaryEntries.Count; + + bool ICollection.IsSynchronized => true; + + object ICollection.SyncRoot => _dictionaryEntries.SyncRoot; + + private static DictionaryEntry ToDictionaryEntry(object? obj) + { + if (obj == null) + { +#if NANOFRAMEWORK_1_0 + throw new ArgumentNullException(); +#else + throw new ArgumentNullException(nameof(obj)); +#endif + } +#if NANOFRAMEWORK_1_0 + return obj as DictionaryEntry ?? throw new InvalidCastException(); +#else + return (DictionaryEntry)obj; +#endif + } + + void ICollection.CopyTo(Array array, int index) => _dictionaryEntries.CopyTo(array, index); + + IEnumerator IEnumerable.GetEnumerator() => _dictionaryEntries.GetEnumerator(); + + /// + /// Add new in to dictionary. + /// + /// Key value. + /// Value instance. + /// Value argument is . + /// The for a specific key is already in the dictionary. + public void Add(Type key, object value) + { +#if !NANOFRAMEWORK_1_0 + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } +#else + if (value == null) + { + throw new ArgumentNullException(); + } +#endif + lock (_dictionaryEntries.SyncRoot) + { +#if NANOFRAMEWORK_1_0 + DictionaryEntry? element = GetElement(key); +#else + DictionaryEntry? element = GetElement(key, out int index); +#endif + if (element?.Value != null) + { +#if !NANOFRAMEWORK_1_0 + throw new ArgumentException(null, nameof(key)); +#else + throw new ArgumentException(); +#endif + } + else + { + if (element == null) + { + _dictionaryEntries.Add(new DictionaryEntry(key, value)); + } + else + { +#if NANOFRAMEWORK_1_0 + element.Value = value; +#else + _dictionaryEntries[index] = new DictionaryEntry(key, value); +#endif + } + } + } + } + + /// + /// Remove from a dictionary by key . + /// + /// Key value. + public void Remove(Type key) + { + lock (_dictionaryEntries.SyncRoot) + { + //// We do not delete the record to avoid breaking the search loop in multi-threaded access +#if NANOFRAMEWORK_1_0 + DictionaryEntry? element = GetElement(key); +#else + DictionaryEntry? element = GetElement(key, out int index); +#endif + if (element != null) + { +#if NANOFRAMEWORK_1_0 + element.Value = null; +#else + _dictionaryEntries[index] = new DictionaryEntry(key, null); +#endif + } + } + } +#if NANOFRAMEWORK_1_0 + private DictionaryEntry? GetElement(Type key) + { + //// We don't use foreach to avoid unnecessary memory allocations + for (int i = 0; i < _dictionaryEntries.Count; i++) + { + DictionaryEntry entry = ToDictionaryEntry(_dictionaryEntries[i]); + if (entry.Key is Type keyType && keyType == key) + { + return entry; + } + } + + return null; + } +#else + private DictionaryEntry? GetElement(Type key, out int index) + { + //// We don't use foreach to avoid unnecessary memory allocations + for (int i = 0; i < _dictionaryEntries.Count; i++) + { + DictionaryEntry entry = ToDictionaryEntry(_dictionaryEntries[i]); + if (entry.Key is Type keyType && keyType == key) + { + index = i; + return entry; + } + } + + index = -1; + return null; + } +#endif + } +} diff --git a/Shared/MessagePack/Exceptions/ConverterNotFoundException.cs b/Shared/MessagePack/Exceptions/ConverterNotFoundException.cs index 801c4d3..db3502b 100644 --- a/Shared/MessagePack/Exceptions/ConverterNotFoundException.cs +++ b/Shared/MessagePack/Exceptions/ConverterNotFoundException.cs @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if NANOFRAMEWORK_1_0 using System; +#endif namespace nanoFramework.MessagePack.Exceptions { diff --git a/Shared/MessagePack/Extensions/DataTypesExtension.cs b/Shared/MessagePack/Extensions/DataTypesExtension.cs index f2c2f47..94bb7ae 100644 --- a/Shared/MessagePack/Extensions/DataTypesExtension.cs +++ b/Shared/MessagePack/Extensions/DataTypesExtension.cs @@ -14,9 +14,9 @@ internal static byte GetHighBits(this DataTypes type, byte bitsCount) internal static string JoinToString(this DataTypes[] types, string separator) { - StringBuilder sb = new(); + StringBuilder sb = new StringBuilder(); - foreach (var item in types) + foreach (DataTypes item in types) { sb.Append(item); sb.Append(separator); diff --git a/Shared/MessagePack/Extensions/NumberConverterHelper.cs b/Shared/MessagePack/Extensions/NumberConverterHelper.cs index 1ff2983..e92902e 100644 --- a/Shared/MessagePack/Extensions/NumberConverterHelper.cs +++ b/Shared/MessagePack/Extensions/NumberConverterHelper.cs @@ -1,8 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if NANOFRAMEWORK_1_0 using System; -using nanoFramework.MessagePack.Dto; +#endif using nanoFramework.MessagePack.Stream; using nanoFramework.MessagePack.Utility; @@ -10,11 +11,6 @@ namespace nanoFramework.MessagePack.Extensions { internal static class NumberConverterHelper { - internal static void WriteByteValue(this byte value, IMessagePackWriter writer) - { - writer.Write(value); - } - internal static void WriteUShortValue(ushort value, IMessagePackWriter writer) { unchecked @@ -46,11 +42,6 @@ internal static sbyte ReadInt8(IMessagePackReader reader) return (sbyte)((int)temp - byte.MaxValue - 1); } - internal static byte ReadUInt8(IMessagePackReader reader) - { - return reader.ReadByte(); - } - internal static ushort ReadUInt16(IMessagePackReader reader) { return (ushort)((reader.ReadByte() << 8) + reader.ReadByte()); @@ -152,7 +143,7 @@ private static bool TryWriteInt8(long value, IMessagePackWriter writer) } writer.Write(DataTypes.Int8); - WriteSByteValue((sbyte)value, writer); + writer.Write((byte)value); return true; } @@ -164,9 +155,9 @@ internal static bool TryGetFixPositiveNumber(DataTypes type, out byte temp) internal static bool TryGetNegativeNumber(DataTypes type, out sbyte temp) { - temp = (sbyte)((byte)type - 1 - byte.MaxValue); - - return type.GetHighBits(3) == DataTypes.NegativeFixNum.GetHighBits(3); + bool isNegative = type.GetHighBits(3) == DataTypes.NegativeFixNum.GetHighBits(3); + temp = (sbyte)(isNegative ? ((byte)type - 1 - byte.MaxValue) : 0); + return isNegative; } internal static bool TryGetInt32(DataTypes type, IMessagePackReader reader, out int result) @@ -187,7 +178,7 @@ internal static bool TryGetInt32(DataTypes type, IMessagePackReader reader, out switch (type) { case DataTypes.UInt8: - result = ReadUInt8(reader); + result = reader.ReadByte(); return true; case DataTypes.UInt16: result = ReadUInt16(reader); @@ -234,7 +225,7 @@ internal static bool TryGetInt64(DataTypes type, IMessagePackReader reader, out switch (type) { case DataTypes.UInt8: - result = ReadUInt8(reader); + result = reader.ReadByte(); return true; case DataTypes.UInt16: result = ReadUInt16(reader); @@ -271,11 +262,6 @@ internal static bool TryGetInt64(DataTypes type, IMessagePackReader reader, out } } - private static void WriteSByteValue(sbyte value, IMessagePackWriter writer) - { - writer.Write((byte)value); - } - private static bool TryWriteUInt8(ulong value, IMessagePackWriter writer) { if (value > byte.MaxValue) @@ -284,7 +270,7 @@ private static bool TryWriteUInt8(ulong value, IMessagePackWriter writer) } writer.Write(DataTypes.UInt8); - ((byte)value).WriteByteValue(writer); + writer.Write((byte)value); return true; } @@ -433,7 +419,7 @@ internal static void WriteInteger(long value, IMessagePackWriter writer) return; } - throw ExceptionUtility.IntSerializationFailure(value); + throw ExceptionUtility.NumberSerializationFailure(value); } internal static void WriteNonNegativeInteger(ulong value, IMessagePackWriter writer) @@ -463,12 +449,12 @@ internal static void WriteNonNegativeInteger(ulong value, IMessagePackWriter wri return; } - throw ExceptionUtility.IntSerializationFailure(value); + throw ExceptionUtility.NumberSerializationFailure(value); } internal static float ReadFloat(IMessagePackReader reader) { - var binary = ReadBytes(reader, 4); + var binary = reader.ReadBytes(4); byte[] bytes; if (BitConverter.IsLittleEndian) { @@ -496,7 +482,7 @@ internal static float ReadFloat(IMessagePackReader reader) internal static double ReadDouble(IMessagePackReader reader) { - var binary = ReadBytes(reader, 8); + var binary = reader.ReadBytes(8); byte[] bytes; if (BitConverter.IsLittleEndian) { @@ -529,10 +515,5 @@ internal static double ReadDouble(IMessagePackReader reader) return BitConverter.ToDouble(bytes, 0); } - - private static ArraySegment ReadBytes(IMessagePackReader reader, uint length) - { - return reader.ReadBytes(length); - } } } diff --git a/Shared/MessagePack/Extensions/ObjectTokenHelper.cs b/Shared/MessagePack/Extensions/ObjectTokenHelper.cs index 14c2749..5f4804f 100644 --- a/Shared/MessagePack/Extensions/ObjectTokenHelper.cs +++ b/Shared/MessagePack/Extensions/ObjectTokenHelper.cs @@ -3,10 +3,9 @@ using System.Collections; using System.Diagnostics.CodeAnalysis; -using nanoFramework.MessagePack.Converters; using nanoFramework.MessagePack.Dto; -using nanoFramework.MessagePack.Exceptions; using nanoFramework.MessagePack.Stream; +using nanoFramework.MessagePack.Utility; namespace nanoFramework.MessagePack.Extensions { @@ -23,13 +22,18 @@ private static Hashtable ReadMap(this IMessagePackReader reader, int length) { var map = new Hashtable(length); - IConverter stringConverter = ConverterContext.GetConverter(typeof(string)); while (length-- > 0) { - string key = (stringConverter.Read(reader) as string) ?? throw new SerializationException("Map key must be a string."); - ArraySegment? value = reader.ReadToken(); + if (ConverterContext.StringConverter.Read(reader) is string key && key != null) + { + ArraySegment? value = reader.ReadToken(); - map[key] = value; + map[key] = value; + } + else + { + throw ExceptionUtility.BadTypeException(DataTypes.Null, DataTypes.FixStr); + } } return map; diff --git a/Shared/MessagePack/MessagePack.projitems b/Shared/MessagePack/MessagePack.projitems index 0a052a2..4c0069c 100644 --- a/Shared/MessagePack/MessagePack.projitems +++ b/Shared/MessagePack/MessagePack.projitems @@ -10,7 +10,6 @@ - @@ -36,6 +35,8 @@ + + diff --git a/Shared/MessagePack/MessagePackSerializer.cs b/Shared/MessagePack/MessagePackSerializer.cs index 0b1e2e0..46b5515 100644 --- a/Shared/MessagePack/MessagePackSerializer.cs +++ b/Shared/MessagePack/MessagePackSerializer.cs @@ -61,10 +61,11 @@ public static void Serialize(object data, MemoryStream stream) /// /// Target object type. /// MessagePack data stream. + /// If , the stream will not be disposed after deserialization, default value is . /// An instance of an target object after deserialization or . - public static object? Deserialize(Type type, MemoryStream stream) + public static object? Deserialize(Type type, MemoryStream stream, bool leaveOpen = false) { - using (var reader = new MemoryStreamReader(stream)) + using (var reader = new MemoryStreamReader(stream, leaveOpen)) { return Deserialize(type, reader); } diff --git a/Shared/MessagePack/Stream/BaseReader.cs b/Shared/MessagePack/Stream/BaseReader.cs index f185917..e2e0416 100644 --- a/Shared/MessagePack/Stream/BaseReader.cs +++ b/Shared/MessagePack/Stream/BaseReader.cs @@ -144,7 +144,7 @@ public void SkipToken() SkipMapItems(NumberConverterHelper.ReadUInt32(this)); return; case DataTypes.Str8: - SkipBytes(NumberConverterHelper.ReadUInt8(this)); + SkipBytes(ReadByte()); return; case DataTypes.Str16: SkipBytes(NumberConverterHelper.ReadUInt16(this)); @@ -153,7 +153,7 @@ public void SkipToken() SkipBytes(NumberConverterHelper.ReadUInt32(this)); return; case DataTypes.Bin8: - SkipBytes(NumberConverterHelper.ReadUInt8(this)); + SkipBytes(ReadByte()); return; case DataTypes.Bin16: SkipBytes(NumberConverterHelper.ReadUInt16(this)); @@ -199,8 +199,7 @@ public void SkipToken() { StartTokenGathering(); SkipToken(); - var gatheredBytes = StopTokenGathering(); - return gatheredBytes; + return StopTokenGathering(); } private static bool TryGetLengthFromFixStr(DataTypes type, out uint length) diff --git a/Shared/MessagePack/Stream/MemoryStreamReader.cs b/Shared/MessagePack/Stream/MemoryStreamReader.cs index 693e135..575bfd5 100644 --- a/Shared/MessagePack/Stream/MemoryStreamReader.cs +++ b/Shared/MessagePack/Stream/MemoryStreamReader.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #if NANOFRAMEWORK_1_0 @@ -13,11 +13,13 @@ namespace nanoFramework.MessagePack.Stream internal sealed class MemoryStreamReader : BaseReader, IDisposable { private readonly MemoryStream _stream; + private readonly bool _leaveOpen; private long _gatheringStartPosition; - public MemoryStreamReader(MemoryStream stream) + public MemoryStreamReader(MemoryStream stream, bool leaveOpen) { _stream = stream; + _leaveOpen = leaveOpen; } public override byte ReadByte() @@ -44,7 +46,10 @@ public override void Seek(long offset, SeekOrigin origin) public void Dispose() { - _stream.Dispose(); + if (!_leaveOpen) + { + _stream.Dispose(); + } } private byte[] ReadBytesInternal(uint length) @@ -77,7 +82,6 @@ private byte[] ReadBytesInternal(uint length) } return null; - } protected override void StartTokenGathering() diff --git a/Shared/MessagePack/Stream/MemoryStreamWriter.cs b/Shared/MessagePack/Stream/MemoryStreamWriter.cs index 4d86877..8d34e4d 100644 --- a/Shared/MessagePack/Stream/MemoryStreamWriter.cs +++ b/Shared/MessagePack/Stream/MemoryStreamWriter.cs @@ -42,7 +42,7 @@ public void WriteArrayHeader(uint length) { if (length <= 15) { - NumberConverterHelper.WriteByteValue((byte)((byte)DataTypes.FixArray + length), this); + Write((byte)((byte)DataTypes.FixArray + length)); return; } @@ -62,7 +62,7 @@ public void WriteMapHeader(uint length) { if (length <= 15) { - NumberConverterHelper.WriteByteValue((byte)((byte)DataTypes.FixMap + length), this); + Write((byte)((byte)DataTypes.FixMap + length)); return; } diff --git a/Shared/MessagePack/Utility/ExceptionUtility.cs b/Shared/MessagePack/Utility/ExceptionUtility.cs index 4e3345c..7e1d808 100644 --- a/Shared/MessagePack/Utility/ExceptionUtility.cs +++ b/Shared/MessagePack/Utility/ExceptionUtility.cs @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if NANOFRAMEWORK_1_0 using System; +#endif using nanoFramework.MessagePack.Exceptions; using nanoFramework.MessagePack.Extensions; @@ -14,14 +16,9 @@ public static Exception BadTypeException(DataTypes actual, params DataTypes[] ex return new SerializationException($"Got {actual:G} (0x{actual:X}), while expecting one of these: {expectedCodes.JoinToString(", ")}"); } - public static Exception CantReadStringAsBinary() - { - return new SerializationException($"Reading a string as a byte array is disabled. Set 'binaryCompatibilityMode' parameter in MsgPackContext constructor to true to enable it"); - } - public static Exception NotEnoughBytes(int actual, int expected) { - return NotEnoughBytes((long)actual, (long)expected); + return NotEnoughBytes((long)actual, (long)expected); } public static Exception NotEnoughBytes(long actual, long expected) @@ -31,20 +28,15 @@ public static Exception NotEnoughBytes(long actual, long expected) public static Exception NoConverterForCollectionElement(Type type, string elementName) { - return new SerializationException($"Provide converter for {elementName}: {type.Name}"); - } - - public static Exception IntDeserializationFailure(DataTypes type) - { - return new SerializationException($"Waited for an int, got {type:G} (0x{type:X})"); + return new SerializationException($"No converter provided for element '{elementName}' of type {type.Name}."); } - public static Exception IntSerializationFailure(long value) + public static Exception NumberSerializationFailure(long value) { - return IntSerializationFailure((ulong) value); + return NumberSerializationFailure((ulong)value); } - public static Exception IntSerializationFailure(ulong value) + public static Exception NumberSerializationFailure(ulong value) { return new SerializationException($"Can't serialize {value}"); } diff --git a/Shared/MessagePack/Utility/FieldUtility.cs b/Shared/MessagePack/Utility/FieldUtility.cs index ae8d787..4e4368d 100644 --- a/Shared/MessagePack/Utility/FieldUtility.cs +++ b/Shared/MessagePack/Utility/FieldUtility.cs @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if NANOFRAMEWORK_1_0 using System; +#endif using System.Collections; using System.Reflection; using nanoFramework.MessagePack.Dto; @@ -10,17 +12,11 @@ namespace nanoFramework.MessagePack.Utility { internal static class FieldUtility { -#nullable enable public static void Map(Type targetType, ArrayList mappings) { - var fields = GetFields(targetType); + FieldInfo[] fields = GetFields(targetType); - if (fields == null || fields.Length == 0) - { - return; - } - - foreach (var field in fields) + foreach (FieldInfo field in fields) { mappings.Add(new MemberMapping(field)); } @@ -35,16 +31,11 @@ private static FieldInfo[] GetFields(Type type) return (FieldInfo[])list.ToArray(typeof(FieldInfo)); } - private static void GetFields(Type? type, ArrayList list) + private static void GetFields(Type type, ArrayList list) { - if (type == null) - { - return; - } - - var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance); + FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance); - foreach (var field in fields) + foreach (FieldInfo field in fields) { if (field.DeclaringType == type) { @@ -52,7 +43,10 @@ private static void GetFields(Type? type, ArrayList list) } } - GetFields(type.BaseType, list); + if (type.BaseType != null) + { + GetFields(type.BaseType, list); + } } } } diff --git a/Shared/MessagePack/Utility/PropertyUtility.cs b/Shared/MessagePack/Utility/PropertyUtility.cs index ab55e4c..8548061 100644 --- a/Shared/MessagePack/Utility/PropertyUtility.cs +++ b/Shared/MessagePack/Utility/PropertyUtility.cs @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#if NANOFRAMEWORK_1_0 using System; +#endif using System.Collections; using System.Reflection; using nanoFramework.MessagePack.Dto; @@ -12,114 +14,16 @@ internal static class PropertyUtility { internal static void Map(Type targetType, ArrayList mappings) { - var properties = GetProperties(targetType); - - if (properties == null || properties.Length == 0) - { - return; - } - - foreach (var property in properties) - { - mappings.Add(new MemberMapping(property)); - } - } #if NANOFRAMEWORK_1_0 - private static MethodInfo[] GetProperties(Type type) - { - var list = new ArrayList(); - - GetProperties(type, list); - - return (MethodInfo[])list.ToArray(typeof(MethodInfo)); - } - - private static void GetProperties(Type type, ArrayList list) - { - if (type == null) - { - return; - } - - MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); - - foreach (MethodInfo method in methods) - { - if (ShouldSerializeMethod(method)) - { - list.Add(method); - } - } - - //GetProperties(type.BaseType!, list, methodPrefix); - } - - private static bool ShouldSerializeMethod(MethodInfo method) - { - // We care only about property getters when serializing and setter deserializing - if (!method.Name.StartsWith(MemberMapping.GET_) && !method.Name.StartsWith(MemberMapping.SET_)) - { - return false; - } - - // Ignore abstract and virtual objects - if (method.IsAbstract) - { - return false; - } - - // Ignore static methods - if (method.IsStatic) - { - return false; - } - - // Ignore delegates and MethodInfos - if ((method.ReturnType == typeof(Delegate)) || - (method.ReturnType == typeof(MulticastDelegate)) || - (method.ReturnType == typeof(MethodInfo))) - { - return false; - } - - // Ditto for DeclaringType - if ((method.DeclaringType == typeof(Delegate)) || - (method.DeclaringType == typeof(MulticastDelegate))) - { - return false; - } - - return true; - } + PropertyInfo[] properties = MemberPropertyInfo.GetProperties(targetType, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); #else - private static PropertyInfo[] GetProperties(Type type) - { - var list = new ArrayList(); - - GetProperties(type, list); - - return (PropertyInfo[])list.ToArray(typeof(PropertyInfo)); - } - - private static void GetProperties(Type type, ArrayList list) - { - if (type == null) - { - return; - } - - PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + PropertyInfo[] properties = targetType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); +#endif foreach (PropertyInfo property in properties) { - if (property.DeclaringType == type) //skip fields not declared on type, we will find it in a later recursion - { - list.Add(property); - } + mappings.Add(new MemberMapping(property)); } - - GetProperties(type.BaseType!, list); } -#endif } } From a502e159a5fdf7fc722ade9b47e9f4c5232134f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Tue, 3 Feb 2026 11:25:58 +0400 Subject: [PATCH 05/27] perf(Add new Unit test for inherited classes) --- UnitTestShared/Helpers/TestsHelper.cs | 2 +- .../TestData/SecureMessageConverter.cs | 4 ++-- UnitTestShared/TestData/TestBaseClass.cs | 16 +++++++++++++ UnitTestShared/TestData/TestInheritorClass.cs | 14 +++++++++++ UnitTestShared/UnitTestShared.projitems | 2 ++ UnitTestShared/UnitTests.cs | 24 +++++++++++++++++++ 6 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 UnitTestShared/TestData/TestBaseClass.cs create mode 100644 UnitTestShared/TestData/TestInheritorClass.cs diff --git a/UnitTestShared/Helpers/TestsHelper.cs b/UnitTestShared/Helpers/TestsHelper.cs index ac52955..0b9df15 100644 --- a/UnitTestShared/Helpers/TestsHelper.cs +++ b/UnitTestShared/Helpers/TestsHelper.cs @@ -198,7 +198,7 @@ internal static string JoinToString(this long[] objects, string joinString) StringBuilder sb = new(); foreach (long b in objects) { - sb.Append(b.ToString()); + sb.Append(b); sb.Append(joinString); } if (sb.Length > 0) diff --git a/UnitTestShared/TestData/SecureMessageConverter.cs b/UnitTestShared/TestData/SecureMessageConverter.cs index 0a9f271..46c367c 100644 --- a/UnitTestShared/TestData/SecureMessageConverter.cs +++ b/UnitTestShared/TestData/SecureMessageConverter.cs @@ -19,7 +19,7 @@ public SecureMessage Read([NotNull] IMessagePackReader reader) for (int i = 0; i < length; i++) { - int wordIndex = (int)intConverter.Read(reader)!; + int wordIndex = (int)intConverter!.Read(reader)!; sb.Append(SharedWordDictionary.WordDictionary[wordIndex]); sb.Append(' '); } @@ -41,7 +41,7 @@ public void Write(SecureMessage value, [NotNull] IMessagePackWriter writer) foreach (var word in messageWords) { int wordIndex = SharedWordDictionary.WordDictionary.IndexOf(word); - intConverter.Write(wordIndex, writer); + intConverter!.Write(wordIndex, writer); } } diff --git a/UnitTestShared/TestData/TestBaseClass.cs b/UnitTestShared/TestData/TestBaseClass.cs new file mode 100644 index 0000000..c3b5138 --- /dev/null +++ b/UnitTestShared/TestData/TestBaseClass.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace UnitTestShared.TestData +{ + public abstract class TestBaseClass + { + public string BaseField = "baseField"; + + public abstract string Name { get; set; } + + public virtual int VirtualProperty { get; set; } = 100; + + public bool SimpleProperty { get; set; } = false; + } +} diff --git a/UnitTestShared/TestData/TestInheritorClass.cs b/UnitTestShared/TestData/TestInheritorClass.cs new file mode 100644 index 0000000..01040cf --- /dev/null +++ b/UnitTestShared/TestData/TestInheritorClass.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace UnitTestShared.TestData +{ + internal class TestInheritorClass : TestBaseClass + { + public string SimpleField = string.Empty; + + public override string Name { get; set; } = string.Empty; + + public override int VirtualProperty { get; set; } = -100; + } +} diff --git a/UnitTestShared/UnitTestShared.projitems b/UnitTestShared/UnitTestShared.projitems index 8eca298..2812f72 100644 --- a/UnitTestShared/UnitTestShared.projitems +++ b/UnitTestShared/UnitTestShared.projitems @@ -12,9 +12,11 @@ + + diff --git a/UnitTestShared/UnitTests.cs b/UnitTestShared/UnitTests.cs index baa46c5..f9040c1 100644 --- a/UnitTestShared/UnitTests.cs +++ b/UnitTestShared/UnitTests.cs @@ -87,6 +87,7 @@ public void TestConverterContext() Assert.IsNotNull(converter); converter = ConverterContext.GetConverter(typeof(ushort[])); Assert.IsNotNull(converter); + converter = ConverterContext.GetConverter(typeof(Hashtable)); Assert.IsNotNull(ConverterContext.NullConverter); @@ -301,5 +302,28 @@ public void ArrayAndHashtableTest() Assert.AreEqual(entry.Value, hashtableValue[entry.Key]); } } + + [TestMethod] + public void InheritorClassTest() + { + TestInheritorClass test = new TestInheritorClass() + { + Name = nameof(TestInheritorClass), + SimpleProperty = true, + SimpleField = "SimpleField", + BaseField = "Override" + }; + + var resultBytes = MessagePackSerializer.Serialize(test); + Debug.WriteLine($"Serialize byte size: {resultBytes.Length}"); + var testResult = (TestInheritorClass)MessagePackSerializer.Deserialize(typeof(TestInheritorClass), resultBytes)!; + + Assert.AreEqual(test.Name, testResult.Name); + Assert.AreEqual(test.SimpleProperty, testResult.SimpleProperty); + Assert.AreEqual(test.VirtualProperty, testResult.VirtualProperty); + Assert.AreEqual(-100, testResult.VirtualProperty); + Assert.AreEqual(test.SimpleField, testResult.SimpleField); + Assert.AreEqual(test.BaseField, testResult.BaseField); + } } } From ad258922b86a3d2321058e5a1105a8fa4fdd05e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Tue, 3 Feb 2026 12:11:01 +0400 Subject: [PATCH 06/27] perf(Added new type compare benchmark); perf(The data for comparing serialization and deserialization speeds has been replaced with more relevant data); --- .../Base/BaseIterationBenchmark.cs | 20 +- .../Data/ComparativeTestObjects.cs | 477 ++---------------- .../Data/ReferenceTestObjects.cs | 6 +- .../ComparativeDeserializationBenchmark.cs | 37 +- .../ReferenceTypesDeserializationBenchmark.cs | 17 +- .../ValueTypesDeserializationBenchmark.cs | 15 +- .../Program.cs | 47 +- .../ComparativeSerializationBenchmark.cs | 35 +- .../ReferenceTypesSerializationBenchmark.cs | 15 +- .../ValueTypesSerializationBenchmark.cs | 15 +- .../TypeCompareBenchmark.cs | 54 ++ ...nanoFramework.MessagePack.Benchmark.nfproj | 5 +- 12 files changed, 206 insertions(+), 537 deletions(-) create mode 100644 nanoFramework.MessagePack.Benchmark/TypeCompareBenchmark.cs diff --git a/nanoFramework.MessagePack.Benchmark/Base/BaseIterationBenchmark.cs b/nanoFramework.MessagePack.Benchmark/Base/BaseIterationBenchmark.cs index 0b5761f..d2f710e 100644 --- a/nanoFramework.MessagePack.Benchmark/Base/BaseIterationBenchmark.cs +++ b/nanoFramework.MessagePack.Benchmark/Base/BaseIterationBenchmark.cs @@ -1,19 +1,25 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; + namespace nanoFramework.MessagePack.Benchmark.Base { - using System; - /// /// Base benchmark class. /// public abstract class BaseIterationBenchmark { - /// - /// Internal iteration count. - /// - protected virtual int _iterationCount => 20; + private const int VirtualDeviceIterationCount = 20; + private const int PhysicalDeviceIterationCount = 1; + private const string VirtualDeviceName = "Virtual nanoDevice"; + + private static readonly int DefaultIterationCount; + + static BaseIterationBenchmark() + { + DefaultIterationCount = VirtualDeviceName == Runtime.Native.SystemInfo.TargetName ? VirtualDeviceIterationCount : PhysicalDeviceIterationCount; + } /// /// Call iteration benchmark method. @@ -29,7 +35,7 @@ protected void RunInIteration(Action methodToRun) else { int step = 0; - while (step++ < _iterationCount) + while (step++ < DefaultIterationCount) { methodToRun(); } diff --git a/nanoFramework.MessagePack.Benchmark/Data/ComparativeTestObjects.cs b/nanoFramework.MessagePack.Benchmark/Data/ComparativeTestObjects.cs index 6b530ad..708ada2 100644 --- a/nanoFramework.MessagePack.Benchmark/Data/ComparativeTestObjects.cs +++ b/nanoFramework.MessagePack.Benchmark/Data/ComparativeTestObjects.cs @@ -1,12 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; +using System.Collections; +using System.Runtime.Serialization.Formatters.Binary; +using nanoFramework.Json; + namespace nanoFramework.MessagePack.Benchmark.Data { - using System; - using System.Runtime.Serialization.Formatters.Binary; - using nanoFramework.Json; - /// /// Test data. /// @@ -16,108 +17,43 @@ internal class ComparativeTestObjects /// Test json text. /// internal const string TestJson = @"{ - ""StatusUpdateTime"": ""0001-01-01T00:00:00Z"", -""LastActivityTime"": ""2021-06-03T05:52:41.4683112Z"", -""Web_app"": { - ""Servlet"": [ - { - ""Servlet_name"": ""cofaxCDS"", - ""Servlet_class"": ""org.cofax.cds.CDSServlet"", - ""Init_param"": { - ""ConfigGlossaryInstallationAt"": ""Philadelphia, PA"", - ""ConfigGlossaryAdminEmail"": ""ksm@pobox.com"", - ""ConfigGlossaryPoweredBy"": ""Cofax"", - ""ConfigGlossaryPoweredByIcon"": ""/images/cofax.gif"", - ""ConfigGlossaryPtaticPath"": ""/content/static"", - ""TemplateProcessorClass"": ""org.cofax.WysiwygTemplate"", - ""TemplateLoaderClass"": ""org.cofax.FilesTemplateLoader"", - ""TemplatePath"": ""templates"", - ""TemplateOverridePath"": """", - ""DefaultListTemplate"": ""listTemplate.htm"", - ""DefaultFileTemplate"": ""articleTemplate.htm"", - ""UseJSP"": false, - ""JspListTemplate"": ""listTemplate.jsp"", - ""JspFileTemplate"": ""articleTemplate.jsp"", - ""CachePackageTagsTrack"": 200, - ""CachePackageTagsStore"": 200, - ""CachePackageTagsRefresh"": 60, - ""CacheTemplatesTrack"": 100, - ""CacheTemplatesStore"": 50, - ""CacheTemplatesRefresh"": 15, - ""CachePagesTrack"": 200, - ""CachePagesStore"": 100, - ""CachePagesRefresh"": 10, - ""CachePagesDirtyRead"": 10, - ""SearchEngineListTemplate"": ""forSearchEnginesList.htm"", - ""SearchEngineFileTemplate"": ""forSearchEngines.htm"", - ""SearchEngineRobotsDb"": ""WEB_INF/robots.db"", - ""UseDataStore"": true, - ""DataStoreClass"": ""org.cofax.SqlDataStore"", - ""RedirectionClass"": ""org.cofax.SqlRedirection"", - ""DataStoreName"": ""cofax"", - ""DataStoreDriver"": ""com.microsoft.jdbc.sqlserver.SQLServerDriver"", - ""DataStoreUrl"": ""jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon"", - ""DataStoreUser"": ""sa"", - ""DataStorePassword"": ""dataStoreTestQuery"", - ""DataStoreTestQuery"": ""SET NOCOUNT ON;select test='test';"", - ""DataStoreLogFile"": ""/usr/local/tomcat/logs/datastore.log"", - ""DataStoreInitConns"": 10, - ""DataStoreMaxConns"": 100, - ""DataStoreConnUsageLimit"": 100, - ""DataStoreLogLevel"": ""debug"", - ""MaxUrlLength"": 500}}, - { - ""Servlet_name"": ""cofaxEmail"", - ""Servlet_class"": ""org.cofax.cds.EmailServlet"", - ""Init_param"": { - ""MailHost"": ""mail1"", - ""MailHostOverride"": ""mail2""}}, + ""StartDate"": ""2026-01-27T00:00:00.0000000Z"", + ""WorkingTime"": ""00:02:00"", + ""TestObjects"": [ { - ""Servlet_name"": ""cofaxAdmin"", - ""Servlet_class"": ""org.cofax.cds.AdminServlet""}, - + ""UID"": ""e8048178-b787-4f22-85bc-891b6637d353"", + ""Id"": 1 + }, { - ""Servlet_name"": ""fileServlet"", - ""Servlet_class"": ""org.cofax.cds.FileServlet""}, + ""UID"": ""41B07FC4-AE08-4F9B-B9A7-27E8877708D2"", + ""Id"": 2 + } + ], + ""IntArrayData"": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ], + ""Users"": [ { - ""Servlet_name"": ""cofaxTools"", - ""Servlet_class"": ""org.cofax.cms.CofaxToolsServlet"", - ""Snit_param"": { - ""TemplatePath"": ""toolstemplates/"", - ""Log"": 1, - ""LogLocation"": ""/usr/local/tomcat/logs/CofaxTools.log"", - ""LogMaxSize"": """", - ""DataLog"": 1, - ""DataLogLocation"": ""/usr/local/tomcat/logs/dataLog.log"", - ""DataLogMaxSize"": """", - ""RemovePageCache"": ""/content/admin/remove?cache=pages&id="", - ""RemoveTemplateCache"": ""/content/admin/remove?cache=templates&id="", - ""FileTransferFolder"": ""/usr/local/tomcat/webapps/content/fileTransferFolder"", - ""LookInContext"": 1, - ""AdminGroupID"": 4, - ""BetaServer"": true}}], - ""Servlet_mapping"": { - ""CofaxCDS"": ""/"", - ""CofaxEmail"": ""/cofaxutil/aemail/*"", - ""CofaxAdmin"": ""/admin/*"", - ""FileServlet"": ""/static/*"", - ""CofaxTools"": ""/tools/*""}, - - ""Taglib"": { - ""Taglib_uri"": ""cofax.tld"", - ""Taglib_location"": ""/WEB_INF/tlds/cofax.tld""}}}"; + ""Role"": { + ""Name"": ""Admin"", + ""Id"": 1 + }, + ""IsActive"": true, + ""Name"": ""Test"" + } + ], + ""HashData"": { + ""a"": ""Test"", + ""b"": 123 + } +}"; /// /// Gets json deserialize option. /// internal static readonly JsonSerializerOptions JsonSerializerOptions = new JsonSerializerOptions() { PropertyNameCaseInsensitive = true }; - /// - /// Initializes a new instance of the class. - /// internal ComparativeTestObjects() { - TestObject = (TestObjectClass)JsonConvert.DeserializeObject(TestJson, typeof(TestObjectClass), JsonSerializerOptions); + TestObject = (ComparativeBenchmarkObject)JsonConvert.DeserializeObject(TestJson, typeof(ComparativeBenchmarkObject), JsonSerializerOptions); TestObjectMsgPackBytes = MessagePackSerializer.Serialize(TestObject); TestObjectBinaryBytes = BinaryFormatter.Serialize(TestObject); } @@ -125,7 +61,7 @@ internal ComparativeTestObjects() /// /// Gets test object for deserialize . /// - internal static TestObjectClass TestObject { get; private set; } + internal static ComparativeBenchmarkObject TestObject { get; private set; } /// /// Gets byte array for test object used by . @@ -138,405 +74,96 @@ internal ComparativeTestObjects() internal static byte[] TestObjectBinaryBytes { get; private set; } /// - /// Dummy test serialization object sub class. + /// Dummy main test serialization object class. /// [Serializable] - public class InitParam + public class ComparativeBenchmarkObject { /// /// Gets or sets test property. Not used. /// - public string ConfigGlossaryInstallationAt { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string ConfigGlossaryAdminEmail { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string ConfigGlossaryPoweredBy { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string ConfigGlossaryPoweredByIcon { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string ConfigGlossaryPtaticPath { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string TemplateProcessorClass { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string TemplateLoaderClass { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string TemplatePath { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string TemplateOverridePath { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string DefaultListTemplate { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string DefaultFileTemplate { get; set; } - - /// - /// Gets or sets a value indicating whether . Not used. - /// - public bool UseJSP { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string JspListTemplate { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string JspFileTemplate { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public int CachePackageTagsTrack { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public int CachePackageTagsStore { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public int CachePackageTagsRefresh { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public int CacheTemplatesTrack { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public int CacheTemplatesStore { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public int CacheTemplatesRefresh { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public int CachePagesTrack { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public int CachePagesStore { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public int CachePagesRefresh { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public int CachePagesDirtyRead { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string SearchEngineListTemplate { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string SearchEngineFileTemplate { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string SearchEngineRobotsDb { get; set; } - - /// - /// Gets or sets a value indicating whether . Not used. - /// - public bool UseDataStore { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string DataStoreClass { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string RedirectionClass { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string DataStoreName { get; set; } + public DateTime StartDate { get; set; } /// /// Gets or sets test property. Not used. /// - public string DataStoreDriver { get; set; } + public TimeSpan WorkingTime { get; set; } /// /// Gets or sets test property. Not used. /// - public string DataStoreUrl { get; set; } + public int[] IntArrayData { get; set; } /// /// Gets or sets test property. Not used. /// - public string DataStoreUser { get; set; } + public Hashtable HashData { get; set; } /// /// Gets or sets test property. Not used. /// - public string DataStorePassword { get; set; } + public User[] Users { get; set; } /// /// Gets or sets test property. Not used. /// - public string DataStoreTestQuery { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string DataStoreLogFile { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public int DataStoreInitConns { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public int DataStoreMaxConns { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public int DataStoreConnUsageLimit { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string DataStoreLogLevel { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public int MaxUrlLength { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string MailHost { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string MailHostOverride { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public int Log { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string LogLocation { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string LogMaxSize { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public int DataLog { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string DataLogLocation { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string DataLogMaxSize { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string RemovePageCache { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string RemoveTemplateCache { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string FileTransferFolder { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public int LookInContext { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public int AdminGroupID { get; set; } - - /// - /// Gets or sets a value indicating whether . Not used. - /// - public bool BetaServer { get; set; } + public BenchmarkTestObject[] TestObjects { get; set; } } /// /// Dummy main test serialization object class. /// [Serializable] - public class TestObjectClass + public class BenchmarkTestObject { /// /// Gets or sets test property. Not used. /// - public DateTime StatusUpdateTime { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public DateTime LastActivityTime { get; set; } + public ulong Id { get; set; } /// /// Gets or sets test property. Not used. /// - public WebApp Web_app { get; set; } + public Guid UID { get; set; } } /// - /// Test serialization object sub class. - /// - [Serializable] - public class Servlet - { - /// - /// Gets or sets test property. Not used. - /// - public string Servlet_name { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string Servlet_class { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public InitParam Init_param { get; set; } - } - - /// - /// Dummy test serialization object sub class. + /// Dummy main test serialization object class. /// [Serializable] - public class ServletMapping + public class User { /// /// Gets or sets test property. Not used. /// - public string CofaxCDS { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string CofaxEmail { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string CofaxAdmin { get; set; } + public string Name { get; set; } /// /// Gets or sets test property. Not used. /// - public string FileServlet { get; set; } + public bool IsActive { get; set; } /// /// Gets or sets test property. Not used. /// - public string CofaxTools { get; set; } + public Role Role { get; set; } } /// - /// Dummy test serialization object sub class. - /// - [Serializable] - public class Taglib - { - /// - /// Gets or sets test property. Not used. - /// - public string Taglib_uri { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public string Taglib_location { get; set; } - } - - /// - /// Dummy test serialization object sub class. + /// Dummy main test serialization object class. /// [Serializable] - public class WebApp + public class Role { /// /// Gets or sets test property. Not used. /// - public Servlet[] Servlet { get; set; } - - /// - /// Gets or sets test property. Not used. - /// - public ServletMapping Servlet_mapping { get; set; } + public int Id { get; set; } /// /// Gets or sets test property. Not used. /// - public Taglib Taglib { get; set; } + public string Name { get; set; } } } } diff --git a/nanoFramework.MessagePack.Benchmark/Data/ReferenceTestObjects.cs b/nanoFramework.MessagePack.Benchmark/Data/ReferenceTestObjects.cs index 516e8d5..041cb34 100644 --- a/nanoFramework.MessagePack.Benchmark/Data/ReferenceTestObjects.cs +++ b/nanoFramework.MessagePack.Benchmark/Data/ReferenceTestObjects.cs @@ -1,11 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; +using System.Collections; + namespace nanoFramework.MessagePack.Benchmark.Data { - using System; - using System.Collections; - /// /// Test references objects. /// diff --git a/nanoFramework.MessagePack.Benchmark/DeserializationBenchmarks/ComparativeDeserializationBenchmark.cs b/nanoFramework.MessagePack.Benchmark/DeserializationBenchmarks/ComparativeDeserializationBenchmark.cs index c118e81..bb3d8b2 100644 --- a/nanoFramework.MessagePack.Benchmark/DeserializationBenchmarks/ComparativeDeserializationBenchmark.cs +++ b/nanoFramework.MessagePack.Benchmark/DeserializationBenchmarks/ComparativeDeserializationBenchmark.cs @@ -1,27 +1,22 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Runtime.Serialization.Formatters.Binary; +using nanoFramework.Benchmark; +using nanoFramework.Benchmark.Attributes; +using nanoFramework.Json; +using nanoFramework.MessagePack.Benchmark.Base; +using nanoFramework.MessagePack.Benchmark.Data; +using static nanoFramework.MessagePack.Benchmark.Data.ComparativeTestObjects; + namespace nanoFramework.MessagePack.Benchmark.DeserializationBenchmarks { - using System.Runtime.Serialization.Formatters.Binary; - using nanoFramework.Benchmark; - using nanoFramework.Benchmark.Attributes; - using nanoFramework.Json; - using nanoFramework.MessagePack.Benchmark.Base; - using nanoFramework.MessagePack.Benchmark.Data; - using static nanoFramework.MessagePack.Benchmark.Data.ComparativeTestObjects; - /// /// Comparative deserialization benchmark. /// - [IterationCount(10)] + [IterationCount(5)] public class ComparativeDeserializationBenchmark : BaseIterationBenchmark { - /// - /// public iteration count. - /// - protected override int _iterationCount => 1; - /// /// Deserialization json benchmark. /// @@ -30,31 +25,31 @@ public void JsonDeserializationBenchmark() { RunInIteration(() => { - JsonConvert.DeserializeObject(TestJson, typeof(TestObjectClass), ComparativeTestObjects.JsonSerializerOptions); + _ = JsonConvert.DeserializeObject(TestJson, typeof(ComparativeBenchmarkObject), ComparativeTestObjects.JsonSerializerOptions); }); } /// - /// Deserialization binary array benchmark. + /// Deserialization binary array benchmark. /// [Benchmark] - public void BinaryDeserializationBenchmark() + public void MessagePackDeserializationBenchmark() { RunInIteration(() => { - BinaryFormatter.Deserialize(TestObjectBinaryBytes); + _ = MessagePackSerializer.Deserialize(typeof(ComparativeBenchmarkObject), TestObjectMsgPackBytes); }); } /// - /// Deserialization binary array benchmark. + /// Deserialization binary array benchmark. /// [Benchmark] - public void MessagePackDeserializationBenchmark() + public void BinaryDeserializationBenchmark() { RunInIteration(() => { - MessagePackSerializer.Deserialize(typeof(TestObjectClass), TestObjectMsgPackBytes); + _ = BinaryFormatter.Deserialize(TestObjectBinaryBytes); }); } } diff --git a/nanoFramework.MessagePack.Benchmark/DeserializationBenchmarks/ReferenceTypesDeserializationBenchmark.cs b/nanoFramework.MessagePack.Benchmark/DeserializationBenchmarks/ReferenceTypesDeserializationBenchmark.cs index 01a6e64..444d707 100644 --- a/nanoFramework.MessagePack.Benchmark/DeserializationBenchmarks/ReferenceTypesDeserializationBenchmark.cs +++ b/nanoFramework.MessagePack.Benchmark/DeserializationBenchmarks/ReferenceTypesDeserializationBenchmark.cs @@ -1,14 +1,14 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections; +using nanoFramework.Benchmark; +using nanoFramework.Benchmark.Attributes; +using nanoFramework.MessagePack.Benchmark.Base; +using nanoFramework.MessagePack.Benchmark.Data; + namespace nanoFramework.MessagePack.Benchmark.DeserializationBenchmarks { - using System.Collections; - using nanoFramework.Benchmark; - using nanoFramework.Benchmark.Attributes; - using nanoFramework.MessagePack.Benchmark.Base; - using nanoFramework.MessagePack.Benchmark.Data; - /// /// Reference types deserialization benchmark. /// @@ -35,11 +35,6 @@ public class ReferenceTypesDeserializationBenchmark : BaseIterationBenchmark /// private byte[] testHashtableBytes; - /// - /// public iteration count. - /// - protected override int _iterationCount => 20; - /// /// Initialize all test data objects. /// diff --git a/nanoFramework.MessagePack.Benchmark/DeserializationBenchmarks/ValueTypesDeserializationBenchmark.cs b/nanoFramework.MessagePack.Benchmark/DeserializationBenchmarks/ValueTypesDeserializationBenchmark.cs index b9446cf..6dbeaee 100644 --- a/nanoFramework.MessagePack.Benchmark/DeserializationBenchmarks/ValueTypesDeserializationBenchmark.cs +++ b/nanoFramework.MessagePack.Benchmark/DeserializationBenchmarks/ValueTypesDeserializationBenchmark.cs @@ -1,13 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; +using nanoFramework.Benchmark; +using nanoFramework.Benchmark.Attributes; +using nanoFramework.MessagePack.Benchmark.Base; + namespace nanoFramework.MessagePack.Benchmark.DeserializationBenchmarks { - using System; - using nanoFramework.Benchmark; - using nanoFramework.Benchmark.Attributes; - using nanoFramework.MessagePack.Benchmark.Base; - /// /// Value types deserialization benchmark. /// @@ -94,11 +94,6 @@ public class ValueTypesDeserializationBenchmark : BaseIterationBenchmark /// private readonly byte[] guidBytes = MessagePackSerializer.Serialize(Guid.NewGuid()); - /// - /// public iteration count. - /// - protected override int _iterationCount => 20; - /// /// Deserialization benchmark. /// diff --git a/nanoFramework.MessagePack.Benchmark/Program.cs b/nanoFramework.MessagePack.Benchmark/Program.cs index 18ad505..111a40c 100644 --- a/nanoFramework.MessagePack.Benchmark/Program.cs +++ b/nanoFramework.MessagePack.Benchmark/Program.cs @@ -1,47 +1,58 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; +using System.Threading; +using nanoFramework.Benchmark; +using nanoFramework.Json; +using nanoFramework.MessagePack.Benchmark.Data; +using nanoFramework.MessagePack.Benchmark.DeserializationBenchmarks; +using nanoFramework.MessagePack.Benchmark.SerializationBenchmarks; + namespace nanoFramework.MessagePack.Benchmark { - using System; - using System.Threading; - using nanoFramework.Benchmark; - using nanoFramework.Json; - using nanoFramework.MessagePack.Benchmark.Data; - using nanoFramework.MessagePack.Benchmark.DeserializationBenchmarks; - using nanoFramework.MessagePack.Benchmark.SerializationBenchmarks; - /// /// Main program /// internal class Program { + private const int BannerWidth = 63; + private const int BannerPadWidth = 10; + private const int SubBannerWidth = 43; + + /// /// Enter point for run all benchmarks /// internal static void Main() { - Console.WriteLine("********** Starting benchmarks **********"); + string starPad = new string('*', BannerPadWidth); + Console.WriteLine($"{starPad} Starting benchmarks on {Runtime.Native.SystemInfo.TargetName} {starPad}"); BenchmarkRunner.RunClass(typeof(ReferenceTypesDeserializationBenchmark)); BenchmarkRunner.RunClass(typeof(ValueTypesDeserializationBenchmark)); BenchmarkRunner.RunClass(typeof(ReferenceTypesSerializationBenchmark)); BenchmarkRunner.RunClass(typeof(ValueTypesSerializationBenchmark)); + BenchmarkRunner.RunClass(typeof(TypeCompareBenchmark)); var testData = new ComparativeTestObjects(); + string bannerTopBottomLine = new string('=', BannerWidth); + string bannerPad = new string('=', BannerPadWidth); + string subBannerLine = new string(' ', SubBannerWidth); + Console.WriteLine(); Console.WriteLine(); - Console.WriteLine("==============================================================="); - Console.WriteLine("========== Comparative benchmarks data =========="); - Console.WriteLine("========== =========="); - Console.WriteLine($"========== Json string size: {JsonConvert.SerializeObject(ComparativeTestObjects.TestObject).Length} bytes =========="); - Console.WriteLine($"========== BinaryFormatter array size: {ComparativeTestObjects.TestObjectBinaryBytes.Length} bytes =========="); - Console.WriteLine($"========== MessagePack array size: {ComparativeTestObjects.TestObjectMsgPackBytes.Length} bytes =========="); - Console.WriteLine("========== =========="); - Console.WriteLine("==============================================================="); + Console.WriteLine(bannerTopBottomLine); + Console.WriteLine($"{bannerPad} Comparative benchmarks data {bannerPad}"); + Console.WriteLine($"{bannerPad}{subBannerLine}{bannerPad}"); + Console.WriteLine($"{bannerPad} Json string size: {JsonConvert.SerializeObject(ComparativeTestObjects.TestObject).Length} bytes {bannerPad}"); + Console.WriteLine($"{bannerPad} MessagePack array size: {ComparativeTestObjects.TestObjectMsgPackBytes.Length} bytes {bannerPad}"); + Console.WriteLine($"{bannerPad} BinaryFormatter array size: {ComparativeTestObjects.TestObjectBinaryBytes.Length} bytes {bannerPad}"); + Console.WriteLine($"{bannerPad}{subBannerLine}{bannerPad}"); + Console.WriteLine(bannerTopBottomLine); BenchmarkRunner.RunClass(typeof(ComparativeDeserializationBenchmark)); BenchmarkRunner.RunClass(typeof(ComparativeSerializationBenchmark)); - Console.WriteLine("********** Completed benchmarks **********"); + Console.WriteLine($"{starPad} Completed benchmarks {starPad}"); Thread.Sleep(Timeout.Infinite); } diff --git a/nanoFramework.MessagePack.Benchmark/SerializationBenchmarks/ComparativeSerializationBenchmark.cs b/nanoFramework.MessagePack.Benchmark/SerializationBenchmarks/ComparativeSerializationBenchmark.cs index 23e9ecf..0e0eed1 100644 --- a/nanoFramework.MessagePack.Benchmark/SerializationBenchmarks/ComparativeSerializationBenchmark.cs +++ b/nanoFramework.MessagePack.Benchmark/SerializationBenchmarks/ComparativeSerializationBenchmark.cs @@ -1,26 +1,21 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Runtime.Serialization.Formatters.Binary; +using nanoFramework.Benchmark; +using nanoFramework.Benchmark.Attributes; +using nanoFramework.Json; +using nanoFramework.MessagePack.Benchmark.Base; +using nanoFramework.MessagePack.Benchmark.Data; + namespace nanoFramework.MessagePack.Benchmark.SerializationBenchmarks { - using System.Runtime.Serialization.Formatters.Binary; - using nanoFramework.Benchmark; - using nanoFramework.Benchmark.Attributes; - using nanoFramework.Json; - using nanoFramework.MessagePack.Benchmark.Base; - using nanoFramework.MessagePack.Benchmark.Data; - /// /// Comparative serialization benchmark. /// - [IterationCount(10)] + [IterationCount(5)] public class ComparativeSerializationBenchmark : BaseIterationBenchmark { - /// - /// public iteration count. - /// - protected override int _iterationCount => 1; - /// /// Serialization json text benchmark. /// @@ -29,31 +24,31 @@ public void JsonSerializationBenchmark() { RunInIteration(() => { - JsonConvert.SerializeObject(ComparativeTestObjects.TestObject); + _ = JsonConvert.SerializeObject(ComparativeTestObjects.TestObject); }); } /// - /// Serialization test benchmark. + /// Serialization test benchmark. /// [Benchmark] - public void BinarySerializationBenchmark() + public void MessagePackSerializationBenchmark() { RunInIteration(() => { - BinaryFormatter.Serialize(ComparativeTestObjects.TestObject); + _ = MessagePackSerializer.Serialize(ComparativeTestObjects.TestObject); }); } /// - /// Serialization test benchmark. + /// Serialization test benchmark. /// [Benchmark] - public void MessagePackSerializationBenchmark() + public void BinarySerializationBenchmark() { RunInIteration(() => { - MessagePackSerializer.Serialize(ComparativeTestObjects.TestObject); + _ = BinaryFormatter.Serialize(ComparativeTestObjects.TestObject); }); } } diff --git a/nanoFramework.MessagePack.Benchmark/SerializationBenchmarks/ReferenceTypesSerializationBenchmark.cs b/nanoFramework.MessagePack.Benchmark/SerializationBenchmarks/ReferenceTypesSerializationBenchmark.cs index 48f9441..cead723 100644 --- a/nanoFramework.MessagePack.Benchmark/SerializationBenchmarks/ReferenceTypesSerializationBenchmark.cs +++ b/nanoFramework.MessagePack.Benchmark/SerializationBenchmarks/ReferenceTypesSerializationBenchmark.cs @@ -1,24 +1,19 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using nanoFramework.Benchmark; +using nanoFramework.Benchmark.Attributes; +using nanoFramework.MessagePack.Benchmark.Base; +using nanoFramework.MessagePack.Benchmark.Data; + namespace nanoFramework.MessagePack.Benchmark.SerializationBenchmarks { - using nanoFramework.Benchmark; - using nanoFramework.Benchmark.Attributes; - using nanoFramework.MessagePack.Benchmark.Base; - using nanoFramework.MessagePack.Benchmark.Data; - /// /// Reference types serialization benchmark. /// [IterationCount(5)] public class ReferenceTypesSerializationBenchmark : BaseIterationBenchmark { - /// - /// public iteration count. - /// - protected override int _iterationCount => 20; - /// /// Serialization benchmark. /// diff --git a/nanoFramework.MessagePack.Benchmark/SerializationBenchmarks/ValueTypesSerializationBenchmark.cs b/nanoFramework.MessagePack.Benchmark/SerializationBenchmarks/ValueTypesSerializationBenchmark.cs index b5b1f39..0495641 100644 --- a/nanoFramework.MessagePack.Benchmark/SerializationBenchmarks/ValueTypesSerializationBenchmark.cs +++ b/nanoFramework.MessagePack.Benchmark/SerializationBenchmarks/ValueTypesSerializationBenchmark.cs @@ -1,13 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; +using nanoFramework.Benchmark; +using nanoFramework.Benchmark.Attributes; +using nanoFramework.MessagePack.Benchmark.Base; + namespace nanoFramework.MessagePack.Benchmark.SerializationBenchmarks { - using System; - using nanoFramework.Benchmark; - using nanoFramework.Benchmark.Attributes; - using nanoFramework.MessagePack.Benchmark.Base; - /// /// Value types serialization benchmark /// @@ -29,11 +29,6 @@ public class ValueTypesSerializationBenchmark : BaseIterationBenchmark /// private readonly string _testString = "Benchmark test"; - /// - /// public iteration count. - /// - protected override int _iterationCount => 20; - /// /// Serialization benchmark. /// diff --git a/nanoFramework.MessagePack.Benchmark/TypeCompareBenchmark.cs b/nanoFramework.MessagePack.Benchmark/TypeCompareBenchmark.cs new file mode 100644 index 0000000..3e69b3e --- /dev/null +++ b/nanoFramework.MessagePack.Benchmark/TypeCompareBenchmark.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using nanoFramework.Benchmark; +using nanoFramework.Benchmark.Attributes; +using nanoFramework.MessagePack.Benchmark.Base; + +namespace nanoFramework.MessagePack.Benchmark +{ + /// + /// Comparative Type compare benchmark. + /// + [IterationCount(5)] + public class TypeCompareBenchmark : BaseIterationBenchmark + { + private const int COMPARE_COUNT = 100; + private readonly Type _intType = typeof(int); + private readonly int _intTypeHash = typeof(int).FullName.GetHashCode(); + + + /// + /// Type FillName hash comparer benchmark. + /// + [Benchmark] + public void TestTypeCompareByNameBenchmark() + { + RunInIteration(() => + { + int count = COMPARE_COUNT; + while (count-- > 0) + { + _ = _intTypeHash == _intType.FullName.GetHashCode(); + } + }); + } + + /// + /// Type instance comparer benchmark. + /// + [Benchmark] + public void TestTypeCompareByTypeBenchmark() + { + RunInIteration(() => + { + int count = COMPARE_COUNT; + while (count-- > 0) + { + _ = _intType == typeof(int); + } + }); + } + } +} diff --git a/nanoFramework.MessagePack.Benchmark/nanoFramework.MessagePack.Benchmark.nfproj b/nanoFramework.MessagePack.Benchmark/nanoFramework.MessagePack.Benchmark.nfproj index ad301b3..67c6f1b 100644 --- a/nanoFramework.MessagePack.Benchmark/nanoFramework.MessagePack.Benchmark.nfproj +++ b/nanoFramework.MessagePack.Benchmark/nanoFramework.MessagePack.Benchmark.nfproj @@ -31,6 +31,7 @@ + @@ -68,10 +69,10 @@ - + - + From 28bec6ade0e5537da51cef11a026daf0b9e399eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Tue, 3 Feb 2026 15:35:30 +0400 Subject: [PATCH 07/27] docs(Updated with benchmark results) --- README.md | 148 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 128 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 09a8817..d4f379f 100644 --- a/README.md +++ b/README.md @@ -250,39 +250,147 @@ After completing these steps, the serialization/deserialization of the object fo ## Benchmarks -The measurements were carried out on the developer's local computer in a virtual nanoDevice: +Comparing data: + ```json + { + "StartDate": "2026-01-27T00:00:00.0000000Z", + "WorkingTime": "00:02:00", + "TestObjects": [ + { + "UID": "e8048178-b787-4f22-85bc-891b6637d353", + "Id": 1 + }, + { + "UID": "41B07FC4-AE08-4F9B-B9A7-27E8877708D2", + "Id": 2 + } + ], + "IntArrayData": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ], + "Users": [ + { + "Role": { + "Name": "Admin", + "Id": 1 + }, + "IsActive": true, + "Name": "Test" + } + ], + "HashData": { + "a": "Test", + "b": 123 + } +} + ``` + +Size after serialization: ```text =============================================================== ========== Comparative benchmarks data ========== ========== ========== -========== Json string size: 3957 bytes ========== -========== BinaryFormatter array size: 1079 bytes ========== -========== MessagePack array size: 2444 bytes ========== +========== Json string size: 336 bytes ========== +========== MessagePack array size: 197 bytes ========== +========== BinaryFormatter array size: 186 bytes ========== ========== ========== =============================================================== +``` + +The measurements were carried out on the developer's local computer in a virtual nanoDevice: + + ```text +********** Starting benchmarks on Virtual nanoDevice ********** + +| ------------------------------------------------------------------------------- | +| MethodName | IterationCount | Mean | Min | Max | +| ------------------------------------------------------------------------------- | +| JsonDeserializationBenchmark | 5 | 94.8 ms | 83 ms | 112 ms | +| MessagePackDeserializationBenchmark | 5 | 49.4 ms | 48 ms | 51 ms | +| BinaryDeserializationBenchmark | 5 | 0.4 ms | 0 ms | 1 ms | +| ------------------------------------------------------------------------------- | + +| ------------------------------------------------------------------------------------------ | +| MethodName | IterationCount | Mean | Min | Max | +| ------------------------------------------------------------------------------------------ | +| JsonSerializationBenchmark | 5 | 57 ms | 51 ms | 63 ms | +| MessagePackSerializationBenchmark | 5 | 41.399999999999997 ms | 40 ms | 44 ms | +| BinarySerializationBenchmark | 5 | 0.2 ms | 0 ms | 1 ms | +| ------------------------------------------------------------------------------------------ | +********** Completed benchmarks ********** + +*Remark: +One iteration is 20 consecutive repetitions! +``` -Console export: ComparativeDeserializationBenchmark benchmark class. +Measurements taken on the ESP32 WROOM device: -| ------------------------------------------------------------------------------ | -| MethodName | IterationCount | Mean | Min | Max | -| ------------------------------------------------------------------------------ | -| JsonDeserializationBenchmark | 10 | 27.5 ms | 22 ms | 37 ms | -| BinaryDeserializationBenchmark | 10 | 0.1 ms | 0 ms | 1 ms | -| MessagePackDeserializationBenchmark | 10 | 23.7 ms | 19 ms | 34 ms | -| ------------------------------------------------------------------------------ | + ```text +********** Starting benchmarks on ESP32_REV3 ********** + +| ------------------------------------------------------------------------------- | +| MethodName | IterationCount | Mean | Min | Max | +| ------------------------------------------------------------------------------- | +| JsonDeserializationBenchmark | 5 | 386 ms | 380 ms | 390 ms | +| MessagePackDeserializationBenchmark | 5 | 188 ms | 180 ms | 190 ms | +| BinaryDeserializationBenchmark | 5 | 4 ms | 0 ms | 10 ms | +| ------------------------------------------------------------------------------- | + +| ----------------------------------------------------------------------------- | +| MethodName | IterationCount | Mean | Min | Max | +| ----------------------------------------------------------------------------- | +| JsonSerializationBenchmark | 5 | 226 ms | 220 ms | 230 ms | +| MessagePackSerializationBenchmark | 5 | 126 ms | 120 ms | 130 ms | +| BinarySerializationBenchmark | 5 | 2 ms | 0 ms | 10 ms | +| ----------------------------------------------------------------------------- | +********** Completed benchmarks ********** +``` -Console export: ComparativeSerializationBenchmark benchmark class. +Measurements taken on the XIAO-ESP32-C3 device: + ```text +********** Starting benchmarks on XIAO_ESP32C3 ********** + +| ------------------------------------------------------------------------------- | +| MethodName | IterationCount | Mean | Min | Max | +| ------------------------------------------------------------------------------- | +| JsonDeserializationBenchmark | 5 | 208 ms | 200 ms | 210 ms | +| MessagePackDeserializationBenchmark | 5 | 98 ms | 90 ms | 100 ms | +| BinaryDeserializationBenchmark | 5 | 0 ms | 0 ms | 0 ms | +| ------------------------------------------------------------------------------- | + +| ----------------------------------------------------------------------------- | +| MethodName | IterationCount | Mean | Min | Max | +| ----------------------------------------------------------------------------- | +| JsonSerializationBenchmark | 5 | 140 ms | 140 ms | 140 ms | +| MessagePackSerializationBenchmark | 5 | 80 ms | 80 ms | 80 ms | +| BinarySerializationBenchmark | 5 | 0 ms | 0 ms | 0 ms | +| ----------------------------------------------------------------------------- | +********** Completed benchmarks ********** +``` -| ---------------------------------------------------------------------------- | -| MethodName | IterationCount | Mean | Min | Max | -| ---------------------------------------------------------------------------- | -| JsonSerializationBenchmark | 10 | 18.9 ms | 16 ms | 25 ms | -| BinarySerializationBenchmark | 10 | 0.1 ms | 0 ms | 1 ms | -| MessagePackSerializationBenchmark | 10 | 9.8 ms | 9 ms | 14 ms | -| ---------------------------------------------------------------------------- | +Measurements taken on the XIAO-ESP32-C6 device: + + ```text +********** Starting benchmarks on ESP32_C6_THREAD ********** + +| ------------------------------------------------------------------------------- | +| MethodName | IterationCount | Mean | Min | Max | +| ------------------------------------------------------------------------------- | +| JsonDeserializationBenchmark | 5 | 112 ms | 110 ms | 120 ms | +| MessagePackDeserializationBenchmark | 5 | 60 ms | 60 ms | 60 ms | +| BinaryDeserializationBenchmark | 5 | 2 ms | 0 ms | 10 ms | +| ------------------------------------------------------------------------------- | + +| -------------------------------------------------------------------------- | +| MethodName | IterationCount | Mean | Min | Max | +| -------------------------------------------------------------------------- | +| JsonSerializationBenchmark | 5 | 68 ms | 60 ms | 70 ms | +| MessagePackSerializationBenchmark | 5 | 48 ms | 40 ms | 50 ms | +| BinarySerializationBenchmark | 5 | 2 ms | 0 ms | 10 ms | +| -------------------------------------------------------------------------- | +********** Completed benchmarks ********** ``` + As it can be seen from the benchmark results above, in what concerns speed and compaction, `MessagePack` performs better than the Json serializer. Comming at no surprise, Binary serialization is the most performant one. ## Acknowledgements From 76af96c811be233706ad9041aba78617724bbdbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Wed, 18 Feb 2026 15:05:53 +0000 Subject: [PATCH 08/27] Update Shared/MessagePack/Converters/UshortConverter.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Shared/MessagePack/Converters/UshortConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Shared/MessagePack/Converters/UshortConverter.cs b/Shared/MessagePack/Converters/UshortConverter.cs index dcaaf57..6d79b67 100644 --- a/Shared/MessagePack/Converters/UshortConverter.cs +++ b/Shared/MessagePack/Converters/UshortConverter.cs @@ -16,7 +16,7 @@ internal class UshortConverter : IConverter #nullable enable public void Write(object? value, [NotNull] IMessagePackWriter writer) { - if(value == null) + if (value == null) { #if NANOFRAMEWORK_1_0 throw new ArgumentNullException(); From 2cd54829b70c9da9e28176b7003e283f8ad6d106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 18 Feb 2026 21:18:04 +0400 Subject: [PATCH 09/27] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Shared/MessagePack/Converters/DateTimeConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Shared/MessagePack/Converters/DateTimeConverter.cs b/Shared/MessagePack/Converters/DateTimeConverter.cs index f6a2605..5a5bcd8 100644 --- a/Shared/MessagePack/Converters/DateTimeConverter.cs +++ b/Shared/MessagePack/Converters/DateTimeConverter.cs @@ -15,7 +15,7 @@ internal class DateTimeConverter : IConverter #nullable enable public void Write(object? value, [NotNull] IMessagePackWriter writer) { - if(value == null) + if (value == null) { #if NANOFRAMEWORK_1_0 throw new ArgumentNullException(); From 7dd06461eb326613abaac49ee03ba2fe209b6e35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 18 Feb 2026 21:21:03 +0400 Subject: [PATCH 10/27] Update Program.cs --- nanoFramework.MessagePack.Benchmark/Program.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/nanoFramework.MessagePack.Benchmark/Program.cs b/nanoFramework.MessagePack.Benchmark/Program.cs index 111a40c..b59ee9b 100644 --- a/nanoFramework.MessagePack.Benchmark/Program.cs +++ b/nanoFramework.MessagePack.Benchmark/Program.cs @@ -20,7 +20,6 @@ internal class Program private const int BannerPadWidth = 10; private const int SubBannerWidth = 43; - /// /// Enter point for run all benchmarks /// From c36a8b7fb2a22bd1e24ac6380418c3d725dac55f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 18 Feb 2026 21:27:28 +0400 Subject: [PATCH 11/27] Update UlongConverter.cs --- Shared/MessagePack/Converters/UlongConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Shared/MessagePack/Converters/UlongConverter.cs b/Shared/MessagePack/Converters/UlongConverter.cs index 42e7054..1c99747 100644 --- a/Shared/MessagePack/Converters/UlongConverter.cs +++ b/Shared/MessagePack/Converters/UlongConverter.cs @@ -16,7 +16,7 @@ internal class UlongConverter : IConverter #nullable enable public void Write(object? value, [NotNull] IMessagePackWriter writer) { - if(value == null) + if (value == null) { #if NANOFRAMEWORK_1_0 throw new ArgumentNullException(); From c2887fef617bc529121ea9b50427e929be0b95aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 18 Feb 2026 21:29:30 +0400 Subject: [PATCH 12/27] Update TypeCompareBenchmark.cs --- nanoFramework.MessagePack.Benchmark/TypeCompareBenchmark.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nanoFramework.MessagePack.Benchmark/TypeCompareBenchmark.cs b/nanoFramework.MessagePack.Benchmark/TypeCompareBenchmark.cs index 3e69b3e..d35dd5e 100644 --- a/nanoFramework.MessagePack.Benchmark/TypeCompareBenchmark.cs +++ b/nanoFramework.MessagePack.Benchmark/TypeCompareBenchmark.cs @@ -20,7 +20,7 @@ public class TypeCompareBenchmark : BaseIterationBenchmark /// - /// Type FillName hash comparer benchmark. + /// Type FullName hash comparer benchmark. /// [Benchmark] public void TestTypeCompareByNameBenchmark() From 880dd4dad75fcc6a1ea36e596d192d3eb715eed5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 18 Feb 2026 21:33:50 +0400 Subject: [PATCH 13/27] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d4f379f..89f4f4f 100644 --- a/README.md +++ b/README.md @@ -391,7 +391,7 @@ Measurements taken on the XIAO-ESP32-C6 device: ********** Completed benchmarks ********** ``` -As it can be seen from the benchmark results above, in what concerns speed and compaction, `MessagePack` performs better than the Json serializer. Comming at no surprise, Binary serialization is the most performant one. +As it can be seen from the benchmark results above, in what concerns speed and compaction, `MessagePack` performs better than the Json serializer. Coming at no surprise, Binary serialization is the most performant one. ## Acknowledgements From 09050380f308a88de543bccda8a3a7b8c02e841a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 18 Feb 2026 21:38:52 +0400 Subject: [PATCH 14/27] Update DoubleConverter.cs --- Shared/MessagePack/Converters/DoubleConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Shared/MessagePack/Converters/DoubleConverter.cs b/Shared/MessagePack/Converters/DoubleConverter.cs index 676d22f..6db06c4 100644 --- a/Shared/MessagePack/Converters/DoubleConverter.cs +++ b/Shared/MessagePack/Converters/DoubleConverter.cs @@ -16,7 +16,7 @@ internal class DoubleConverter : IConverter #nullable enable public void Write(object? value, [NotNull] IMessagePackWriter writer) { - if(value == null) + if (value == null) { #if NANOFRAMEWORK_1_0 throw new ArgumentNullException(); From dd2a6632ec578ab5a1f6e574f54803d23f275bbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 18 Feb 2026 21:39:52 +0400 Subject: [PATCH 15/27] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Shared/MessagePack/Converters/FloatConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Shared/MessagePack/Converters/FloatConverter.cs b/Shared/MessagePack/Converters/FloatConverter.cs index 65c4602..fee3a99 100644 --- a/Shared/MessagePack/Converters/FloatConverter.cs +++ b/Shared/MessagePack/Converters/FloatConverter.cs @@ -16,7 +16,7 @@ internal class FloatConverter : IConverter #nullable enable public void Write(object? value, [NotNull] IMessagePackWriter writer) { - if(value == null) + if (value == null) { #if NANOFRAMEWORK_1_0 throw new ArgumentNullException(); From 50dcfe0a1f12fbfe86d16547b10fd57d629458ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 18 Feb 2026 21:42:38 +0400 Subject: [PATCH 16/27] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Shared/MessagePack/Converters/SimpleArrayConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Shared/MessagePack/Converters/SimpleArrayConverter.cs b/Shared/MessagePack/Converters/SimpleArrayConverter.cs index 3fb84a8..6e4d2b2 100644 --- a/Shared/MessagePack/Converters/SimpleArrayConverter.cs +++ b/Shared/MessagePack/Converters/SimpleArrayConverter.cs @@ -19,7 +19,7 @@ public class SimpleArrayConverter : IConverter private readonly Type _elementType; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the SimpleArrayConverter class. /// /// Type of array element. public SimpleArrayConverter(Type elementType) From 4e2b8dcf70c32487a8509a844e41a4fdf72318de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 18 Feb 2026 21:45:25 +0400 Subject: [PATCH 17/27] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Shared/MessagePack/Converters/SimpleArrayConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Shared/MessagePack/Converters/SimpleArrayConverter.cs b/Shared/MessagePack/Converters/SimpleArrayConverter.cs index 6e4d2b2..dd3c117 100644 --- a/Shared/MessagePack/Converters/SimpleArrayConverter.cs +++ b/Shared/MessagePack/Converters/SimpleArrayConverter.cs @@ -41,7 +41,7 @@ public void Write(Array? value, IMessagePackWriter writer) /// Read array from MessagePack stream. /// /// MessagePack stream for reading. - /// Readied array. + /// Read array. public Array? Read(IMessagePackReader reader) { var length = (int)reader.ReadArrayLength(); From e6cddbbd578a9d5c14fcec0e3908681f7bc9c170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 18 Feb 2026 21:47:38 +0400 Subject: [PATCH 18/27] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Shared/MessagePack/Converters/UintConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Shared/MessagePack/Converters/UintConverter.cs b/Shared/MessagePack/Converters/UintConverter.cs index 73d4126..d636d58 100644 --- a/Shared/MessagePack/Converters/UintConverter.cs +++ b/Shared/MessagePack/Converters/UintConverter.cs @@ -16,7 +16,7 @@ internal class UintConverter : IConverter #nullable enable public void Write(object? value, [NotNull] IMessagePackWriter writer) { - if(value == null) + if (value == null) { #if NANOFRAMEWORK_1_0 throw new ArgumentNullException(); From 11f0b705bf94a83036ecea97492fbc4f72bf9d09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 18 Feb 2026 21:52:39 +0400 Subject: [PATCH 19/27] Update MemberMapping.cs --- Shared/MessagePack/Dto/MemberMapping.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Shared/MessagePack/Dto/MemberMapping.cs b/Shared/MessagePack/Dto/MemberMapping.cs index b0eebf3..ed40f73 100644 --- a/Shared/MessagePack/Dto/MemberMapping.cs +++ b/Shared/MessagePack/Dto/MemberMapping.cs @@ -12,7 +12,6 @@ internal class MemberMapping { #nullable enable private readonly FieldInfo? _field; - private readonly PropertyInfo? _property; public MemberMapping(PropertyInfo property) From 78be46ae8a732c3a5a8b1ac84d4df2a01033ef0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 18 Feb 2026 21:56:43 +0400 Subject: [PATCH 20/27] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Shared/MessagePack/Dto/MemberPropertyInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Shared/MessagePack/Dto/MemberPropertyInfo.cs b/Shared/MessagePack/Dto/MemberPropertyInfo.cs index 8b5538e..72c4039 100644 --- a/Shared/MessagePack/Dto/MemberPropertyInfo.cs +++ b/Shared/MessagePack/Dto/MemberPropertyInfo.cs @@ -47,7 +47,7 @@ private MemberPropertyInfo(MethodInfo? getMethod, MethodInfo? setMethod) _setMethodInfo = setMethod; DeclaringType = mi.DeclaringType; - if(mi.Name.Length > 4) + if (mi.Name.Length > 4) { Name = mi.Name.Substring(4); } From 8f627fe78a0f4fa2c06167da0cd41bb008c8d085 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 18 Feb 2026 22:01:29 +0400 Subject: [PATCH 21/27] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Shared/MessagePack/ConverterContext.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Shared/MessagePack/ConverterContext.cs b/Shared/MessagePack/ConverterContext.cs index 97e0245..dd040f0 100644 --- a/Shared/MessagePack/ConverterContext.cs +++ b/Shared/MessagePack/ConverterContext.cs @@ -246,7 +246,7 @@ internal static MemberMapping[] GetMemberMapping(Type targetType) s_mappingDictionary[targetType] = memberMappings; return memberMappings; - } + } } internal static void SerializeObject(Type type, object value, IMessagePackWriter writer) From 6cefe1dba90093a550a047ec355e3c4beff7a321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 18 Feb 2026 22:29:13 +0400 Subject: [PATCH 22/27] Update LongConverter.cs --- Shared/MessagePack/Converters/LongConverter.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Shared/MessagePack/Converters/LongConverter.cs b/Shared/MessagePack/Converters/LongConverter.cs index bf08308..d2b5b34 100644 --- a/Shared/MessagePack/Converters/LongConverter.cs +++ b/Shared/MessagePack/Converters/LongConverter.cs @@ -23,7 +23,6 @@ public void Write(object? value, [NotNull] IMessagePackWriter writer) #else throw new ArgumentNullException(nameof(value)); #endif - } if (value is long longValue) From ada1c020f961a48fa55ee5396937b15db0327505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 18 Feb 2026 22:29:59 +0400 Subject: [PATCH 23/27] Update CharConverter.cs --- Shared/MessagePack/Converters/CharConverter.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Shared/MessagePack/Converters/CharConverter.cs b/Shared/MessagePack/Converters/CharConverter.cs index 9f145a8..98e5560 100644 --- a/Shared/MessagePack/Converters/CharConverter.cs +++ b/Shared/MessagePack/Converters/CharConverter.cs @@ -23,6 +23,7 @@ public void Write(object? value, [NotNull] IMessagePackWriter writer) throw new ArgumentNullException(nameof(value)); #endif } + if (value is char charValue) { ConverterContext.UshortConverter.Write(BitConverter.ToUInt16(BitConverter.GetBytes(charValue), 0), writer); From ac259b612491f3ea931b86cd02d0c8b53d552c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 18 Feb 2026 22:39:16 +0400 Subject: [PATCH 24/27] Update IntConverter.cs --- Shared/MessagePack/Converters/IntConverter.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Shared/MessagePack/Converters/IntConverter.cs b/Shared/MessagePack/Converters/IntConverter.cs index 6cf3696..139849e 100644 --- a/Shared/MessagePack/Converters/IntConverter.cs +++ b/Shared/MessagePack/Converters/IntConverter.cs @@ -24,6 +24,7 @@ public void Write(object? value, [NotNull] IMessagePackWriter writer) throw new ArgumentNullException(nameof(value)); #endif } + if (value is int intValue) { NumberConverterHelper.WriteInteger(intValue, writer); From 201e7162c6d1fa2f82eb795b1f35dd45032685ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 18 Feb 2026 22:40:03 +0400 Subject: [PATCH 25/27] Update ShortConverter.cs --- Shared/MessagePack/Converters/ShortConverter.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Shared/MessagePack/Converters/ShortConverter.cs b/Shared/MessagePack/Converters/ShortConverter.cs index 85fbc33..9fe64fa 100644 --- a/Shared/MessagePack/Converters/ShortConverter.cs +++ b/Shared/MessagePack/Converters/ShortConverter.cs @@ -24,6 +24,7 @@ public void Write(object? value, [NotNull] IMessagePackWriter writer) throw new ArgumentNullException(nameof(value)); #endif } + if (value is short shortValue) { NumberConverterHelper.WriteInteger(shortValue, writer); From 102667f39990e3b6dc3d52c4021ef9c5d54f703f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 18 Feb 2026 22:41:19 +0400 Subject: [PATCH 26/27] Update TimeSpanConverter.cs --- Shared/MessagePack/Converters/TimeSpanConverter.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Shared/MessagePack/Converters/TimeSpanConverter.cs b/Shared/MessagePack/Converters/TimeSpanConverter.cs index ab2bea0..9b0d0fe 100644 --- a/Shared/MessagePack/Converters/TimeSpanConverter.cs +++ b/Shared/MessagePack/Converters/TimeSpanConverter.cs @@ -23,6 +23,7 @@ public void Write(object? value, [NotNull] IMessagePackWriter writer) throw new ArgumentNullException(nameof(value)); #endif } + if (value is TimeSpan timeSpanValue) { ConverterContext.LongConverter.Write(timeSpanValue.Ticks, writer); From d16c20ca2096678de2d8e0dee26be01f5732a84b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 18 Feb 2026 22:44:52 +0400 Subject: [PATCH 27/27] Update ArraySegment.cs --- Shared/MessagePack/Dto/ArraySegment.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Shared/MessagePack/Dto/ArraySegment.cs b/Shared/MessagePack/Dto/ArraySegment.cs index 43a66cb..897487e 100644 --- a/Shared/MessagePack/Dto/ArraySegment.cs +++ b/Shared/MessagePack/Dto/ArraySegment.cs @@ -182,8 +182,8 @@ protected override void StartTokenGathering() /// public class ArraySegmentEnumerator : IEnumerator { - private int _position = -1; private readonly ArraySegment _arraySegment; + private int _position = -1; internal ArraySegmentEnumerator(ArraySegment arraySegment) {