From 94a0ff83457fac0eb05c7faef7f8938c1c8b9e1e 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: Mon, 21 Apr 2025 22:04:51 +0400 Subject: [PATCH 1/5] Removed unnecessary memory allocations. Fix deserialization of a single two-dimensional array and hashtable. Add and updated UnitTest. --- Shared/MessagePack/ConverterContext.cs | 67 +++++-- Shared/MessagePack/Converters/IConverter.cs | 2 +- Shared/MessagePack/Converters/MapConverter.cs | 2 +- .../MessagePack/Converters/StringConverter.cs | 6 +- Shared/MessagePack/Dto/ArraySegment.cs | 189 +++++++++++++----- .../Extensions/NumberConverterHelper.cs | 5 +- Shared/MessagePack/Stream/BaseReader.cs | 86 ++++++-- Shared/MessagePack/Stream/ByteArrayReader.cs | 2 +- .../MessagePack/Stream/MemoryStreamReader.cs | 37 ++-- .../TestData/SecureMessageConverter.cs | 9 +- .../TestData/SharedWordDictionary.cs | 2 +- UnitTestShared/UnitTests.cs | 168 +++++++++++++++- 12 files changed, 463 insertions(+), 112 deletions(-) diff --git a/Shared/MessagePack/ConverterContext.cs b/Shared/MessagePack/ConverterContext.cs index d374c85..387bedd 100644 --- a/Shared/MessagePack/ConverterContext.cs +++ b/Shared/MessagePack/ConverterContext.cs @@ -142,10 +142,17 @@ internal static Hashtable GetMappingsValues(Type targetType, object value) foreach (var memberMapping in memberMappings) { +#if NANOFRAMEWORK_1_0 + if(!memberMapping.OriginalName!.StartsWith(MemberMapping.SET_)) + { +#endif if (memberMapping.TryGetValue(value, out var memberValue) && memberValue != null) { result.Add(memberMapping.Name!, memberValue); } +#if NANOFRAMEWORK_1_0 + } +#endif } return result; } @@ -156,27 +163,38 @@ internal static void SetMappingsValues(Type targetType, object targetObject, Has foreach (var memberMapping in memberMappings) { +#if NANOFRAMEWORK_1_0 + if(!memberMapping.OriginalName!.StartsWith(MemberMapping.GET_)) + { +#endif if (objectValuesMap.Contains(memberMapping.Name!)) { var memberMpToken = (ArraySegment)objectValuesMap[memberMapping.Name!]!; - var memberValueMapType = memberMapping.GetMemberType(); - var converter = GetConverter(memberValueMapType!); - if (converter != null) - { - memberMapping.SetValue(targetObject, converter.Read(new ByteArrayReader((byte[])memberMpToken))!); - } - else + if (memberMpToken != null) { - if (memberValueMapType!.IsArray) + var memberValueMapType = memberMapping.GetMemberType(); + var converter = GetConverter(memberValueMapType!); + if (converter != null) { - memberMapping.SetValue(targetObject, ArrayConverter.Read(new ByteArrayReader((byte[])memberMpToken), memberValueMapType)!); + memberMapping.SetValue(targetObject, converter.Read(memberMpToken)!); } else { - memberMapping.SetValue(targetObject, DeserializeObject(memberValueMapType!, new ByteArrayReader((byte[])memberMpToken))!); + if (memberValueMapType!.IsArray) + { + memberMapping.SetValue(targetObject, ArrayConverter.Read(memberMpToken, memberValueMapType)!); + } + else + { + + memberMapping.SetValue(targetObject, DeserializeObject(memberValueMapType!, memberMpToken)!); + } } } } +#if NANOFRAMEWORK_1_0 + } +#endif } } @@ -234,6 +252,16 @@ internal static void SerializeObject(Type type, object value, IMessagePackWriter #nullable enable internal static object? DeserializeObject(Type type, IMessagePackReader reader) { + if (type.Name == typeof(IDictionary).Name || type.Name == typeof(Hashtable).Name) + { + return MapConverter.Read(reader); + } + + if (type.IsArray) + { + return ArrayConverter.Read(reader, type); + } + var objectMap = reader.GetMassagePackObjectTokens(); if (objectMap != null && objectMap is Hashtable targetObjectMap) { @@ -284,18 +312,23 @@ internal static void SerializeObject(Type type, object value, IMessagePackWriter } #if NANOFRAMEWORK_1_0 - [MethodImpl(MethodImplOptions.Synchronized)] private static void ThreadSafeAddItemCache(Hashtable hashtable, object key, object value) { if (!hashtable.Contains(key)) { - try - { - hashtable.Add(key, value); - } - catch (Exception ex) + lock(_mappingDictionary) { - Debug.WriteLine($"Error added key: '{key}', value: '{value}'\r\n{ex}"); + try + { + if (!hashtable.Contains(key)) + { + hashtable.Add(key, value); + } + } + catch (Exception ex) + { + Debug.WriteLine($"Error added key: '{key}', value: '{value}'\r\n{ex}"); + } } } } diff --git a/Shared/MessagePack/Converters/IConverter.cs b/Shared/MessagePack/Converters/IConverter.cs index d8443c0..97927cd 100644 --- a/Shared/MessagePack/Converters/IConverter.cs +++ b/Shared/MessagePack/Converters/IConverter.cs @@ -7,7 +7,7 @@ namespace nanoFramework.MessagePack.Converters { /// - /// interface. + /// interface. /// public interface IConverter { diff --git a/Shared/MessagePack/Converters/MapConverter.cs b/Shared/MessagePack/Converters/MapConverter.cs index 29892c3..8aca161 100644 --- a/Shared/MessagePack/Converters/MapConverter.cs +++ b/Shared/MessagePack/Converters/MapConverter.cs @@ -53,7 +53,7 @@ private static void Write(IDictionary value, IMessagePackWriter writer) } #nullable enable - private static Hashtable? Read(IMessagePackReader reader) + internal static Hashtable? Read(IMessagePackReader reader) { var length = reader.ReadMapLength(); return ((long)length) > -1 ? ReadMap(reader, length) : null; diff --git a/Shared/MessagePack/Converters/StringConverter.cs b/Shared/MessagePack/Converters/StringConverter.cs index 9268b24..0de9b93 100644 --- a/Shared/MessagePack/Converters/StringConverter.cs +++ b/Shared/MessagePack/Converters/StringConverter.cs @@ -3,6 +3,7 @@ using System.Diagnostics.CodeAnalysis; using System.Text; +using nanoFramework.MessagePack.Dto; using nanoFramework.MessagePack.Extensions; using nanoFramework.MessagePack.Stream; using nanoFramework.MessagePack.Utility; @@ -58,9 +59,10 @@ private static string Read(IMessagePackReader reader) internal static string ReadString(IMessagePackReader reader, uint length) { - var buffer = (byte[])reader.ReadBytes(length); + ArraySegment arraySegment = reader.ReadBytes(length); + + return Utf8.GetString(arraySegment.SourceBuffer, (int)arraySegment.SourceOffset + arraySegment.Position, (int)arraySegment.Length); - return Utf8.GetString(buffer, 0, buffer.Length); } private static bool TryGetFixStrLength(DataTypes type, out uint length) diff --git a/Shared/MessagePack/Dto/ArraySegment.cs b/Shared/MessagePack/Dto/ArraySegment.cs index aed328d..337ae28 100644 --- a/Shared/MessagePack/Dto/ArraySegment.cs +++ b/Shared/MessagePack/Dto/ArraySegment.cs @@ -2,47 +2,46 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; +using nanoFramework.MessagePack.Stream; using nanoFramework.MessagePack.Utility; +using System.IO; +using System; +using System.Diagnostics; namespace nanoFramework.MessagePack.Dto { /// - /// Segment by byte array. + /// Segment by byte to array. /// - public class ArraySegment : IEnumerable, IEnumerator + public class ArraySegment : BaseReader, IEnumerable { + private int _firstGatheredByte; private readonly byte[] _buffer; private readonly long _offset; private readonly long _length; /// - /// Gets the current position in the segment. + /// Gets byte by array segment /// - public long Position { get; private set; } = -1; - - /// - /// Gets the element corresponding to the current position in the segment. - /// - public object Current + /// The byte index in the array segment + /// Byte value + public byte this[int index] { get { - if (Position >= _length) - { - throw ExceptionUtility.NotEnoughBytes(Position, _length); - } - - try - { - return _buffer[_offset + Position]; - } - catch - { - throw ExceptionUtility.NotEnoughBytes(_offset + Position, _buffer.Length); - } + return _buffer[_offset + index]; } } + internal byte[] SourceBuffer => _buffer; + internal long SourceOffset => _offset; + internal long Length => _length; + + /// + /// Gets the current position in the segment. + /// + public int Position { get; private set; } = 0; + /// /// Initializes a new instance of the class. /// @@ -57,30 +56,41 @@ public ArraySegment(byte[] buffer, long offset, long length) } /// - /// Implicit conversion from byte array to . + /// Reads bytes in an array segment /// - /// - public static implicit operator ArraySegment(byte[] bytes) + /// Required reading length + /// Segment by byte to current segment + public override ArraySegment ReadBytes(uint length) { - return new ArraySegment(bytes, 0, bytes.Length); + var segment = new ArraySegment(_buffer, _offset + Position, length); + Position += (int)length; + return segment; } /// - /// Implicit conversion from to byte array. + /// Move the reading position in the array segment /// - /// Source . - public static explicit operator byte[](ArraySegment segment) + /// Offset in bytes + /// Offset reference point + /// + public override void Seek(long offset, SeekOrigin origin) { - return segment.ToArray(); + Position = origin switch + { + SeekOrigin.Begin => (int)(offset), + SeekOrigin.Current => (int)(Position + offset), + SeekOrigin.End => (int)(_length + offset), + _ => throw new ArgumentOutOfRangeException(nameof(origin), origin.ToString()), + }; } /// . /// Read one byte from the segment. /// /// The byte read. - public byte ReadByte() + public override byte ReadByte() { - if (++Position >= _length) + if (Position >= _length) { throw ExceptionUtility.NotEnoughBytes(Position, _length); } @@ -90,48 +100,125 @@ public byte ReadByte() throw ExceptionUtility.NotEnoughBytes(_offset + Position, _buffer.Length); } - return _buffer[_offset + Position]; + return _buffer[_offset + Position++]; } /// - /// Get bytes enumerator. + /// Implicit conversion from byte array to . /// - /// Enumerator for bytes in segment. - public IEnumerator GetEnumerator() + /// Source byte array. + public static implicit operator ArraySegment(byte[] bytes) { - return this; + return new ArraySegment(bytes, 0, bytes.Length); } /// - /// Go to next byte in array. + /// Implicit conversion from to byte array. /// - /// if the end of the segment is not reached otherwise . - public bool MoveNext() + /// Source . + public static explicit operator byte[](ArraySegment segment) { - Position++; - - return Position < _length && Position + _offset < _buffer.Length; + return segment.ToArray(); } /// - /// Resets the current position to the beginning of the segment. + /// Get bytes enumerator. /// - public void Reset() + /// Enumerator for bytes in segment. + public IEnumerator GetEnumerator() { - Position = -1; + return new ArraySegmentEnumerator(this); } private byte[] ToArray() { var data = new byte[_length]; - ////for (int i = 0; i < data.Length; i++) - ////{ - //// data[i] = _buffer[_offset + i]; - ////} - System.Array.Copy(_buffer, (int)_offset, data, 0, (int)_length); return data; } + + /// + /// Stopping the collection of MessagePack token in + /// + /// Array segment bytes +#nullable enable + protected override ArraySegment? StopTokenGathering() + { + if (_firstGatheredByte <= _length) + { + var result = new ArraySegment(_buffer, (int)_firstGatheredByte + _offset, (int)(Position - _firstGatheredByte)); + _firstGatheredByte = 0; + return result; + } + else + { + _firstGatheredByte = 0; + return null; + } + } + + /// + /// Start the collection of MessagePack token in + /// + protected override void StartTokenGathering() + { + _firstGatheredByte = Position; + } + + /// + /// Enumerator in an array segment + /// + public class ArraySegmentEnumerator : IEnumerator + { + private int _position = -1; + private ArraySegment _arraySegment; + + internal ArraySegmentEnumerator(ArraySegment arraySegment) + { + _arraySegment = arraySegment; + } + /// + /// Gets the element corresponding to the current position in the segment. + /// + public object Current + { + get + { + if (_position >= _arraySegment._length) + { + throw ExceptionUtility.NotEnoughBytes(_position, _arraySegment._length); + } + + try + { + return _arraySegment._buffer[_arraySegment._offset + _position]; + } + catch + { + throw ExceptionUtility.NotEnoughBytes(_arraySegment._offset + _position, _arraySegment._buffer.Length); + } + } + } + + /// + /// Go to next byte in array. + /// + /// if the end of the segment is not reached otherwise . + public bool MoveNext() + { + _position++; + + return _position < _arraySegment._length && _position + _arraySegment._offset < _arraySegment._buffer.Length; + } + + /// + /// Resets the current position to the beginning of the segment. + /// + public void Reset() + { + _position = -1; + } + } } } diff --git a/Shared/MessagePack/Extensions/NumberConverterHelper.cs b/Shared/MessagePack/Extensions/NumberConverterHelper.cs index 94cdc02..f112459 100644 --- a/Shared/MessagePack/Extensions/NumberConverterHelper.cs +++ b/Shared/MessagePack/Extensions/NumberConverterHelper.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using nanoFramework.MessagePack.Dto; using nanoFramework.MessagePack.Stream; using nanoFramework.MessagePack.Utility; @@ -541,9 +542,9 @@ internal static double ReadDouble(IMessagePackReader reader) return BitConverter.ToDouble(bytes, 0); } - private static byte[] ReadBytes(IMessagePackReader reader, uint length) + private static ArraySegment ReadBytes(IMessagePackReader reader, uint length) { - return (byte[])reader.ReadBytes(length); + return reader.ReadBytes(length); } } } diff --git a/Shared/MessagePack/Stream/BaseReader.cs b/Shared/MessagePack/Stream/BaseReader.cs index 851123d..26fe017 100644 --- a/Shared/MessagePack/Stream/BaseReader.cs +++ b/Shared/MessagePack/Stream/BaseReader.cs @@ -8,14 +8,35 @@ namespace nanoFramework.MessagePack.Stream { - internal abstract class BaseReader : IMessagePackReader + /// + /// Base class for MessagePack reader + /// + public abstract class BaseReader : IMessagePackReader { + /// + /// Read byte from MessagePack + /// + /// Reading byte public abstract byte ReadByte(); + /// + /// Read bytes from MessagePack + /// + /// Length to read + /// Reading bytes public abstract ArraySegment ReadBytes(uint length); + /// + /// Moving the current read position in the array + /// + /// Offset in bytes + /// Offset reference point public abstract void Seek(long offset, SeekOrigin origin); + /// + /// Read length MessagePack array + /// + /// Length MessagePack array public uint ReadArrayLength() { var type = ReadDataType(); @@ -38,6 +59,10 @@ public uint ReadArrayLength() throw ExceptionUtility.BadTypeException(type, DataTypes.Array16, DataTypes.Array32, DataTypes.FixArray, DataTypes.Null); } + /// + /// Read length MessagePack map + /// + /// Count elements in map public uint ReadMapLength() { var type = ReadDataType(); @@ -61,11 +86,19 @@ public uint ReadMapLength() throw ExceptionUtility.BadTypeException(type, DataTypes.Map16, DataTypes.Map32, DataTypes.FixMap, DataTypes.Null); } + /// + /// Read length MessagePack data type + /// + /// MessagePack data type public virtual DataTypes ReadDataType() { return (DataTypes)ReadByte(); } + /// + /// Skip MessagePack item in byte array + /// + /// public void SkipToken() { var dataType = ReadDataType(); @@ -152,7 +185,12 @@ public void SkipToken() throw new System.ArgumentOutOfRangeException(); } + #nullable enable + /// + /// Read MessagePack item in byte array + /// + /// Array segment contained MessagePack item bytes public ArraySegment? ReadToken() { StartTokenGathering(); @@ -160,24 +198,13 @@ public void SkipToken() var gatheredBytes = StopTokenGathering(); return gatheredBytes; } + private static bool TryGetLengthFromFixStr(DataTypes type, out uint length) { length = type - DataTypes.FixStr; return type.GetHighBits(3) == DataTypes.FixStr.GetHighBits(3); } - protected static bool TryGetLengthFromFixArray(DataTypes type, out uint length) - { - length = type - DataTypes.FixArray; - return type.GetHighBits(4) == DataTypes.FixArray.GetHighBits(4); - } - - protected static bool TryGetLengthFromFixMap(DataTypes type, out uint length) - { - length = type - DataTypes.FixMap; - return type.GetHighBits(4) == DataTypes.FixMap.GetHighBits(4); - } - private void SkipMapItems(uint count) { while (count > 0) @@ -201,9 +228,40 @@ private void SkipBytes(uint bytesCount) { Seek(bytesCount, SeekOrigin.Current); } - + + /// + /// Try getting length fixed MessagePack Array + /// + /// MessagePack Array type + /// Out length MessagePack Array + /// True if luck otherwise false + protected static bool TryGetLengthFromFixArray(DataTypes type, out uint length) + { + length = type - DataTypes.FixArray; + return type.GetHighBits(4) == DataTypes.FixArray.GetHighBits(4); + } + + /// + /// Try getting length fixed MessagePack Map + /// + /// MessagePack Map type + /// Out length MessagePack Map + /// True if luck otherwise false + protected static bool TryGetLengthFromFixMap(DataTypes type, out uint length) + { + length = type - DataTypes.FixMap; + return type.GetHighBits(4) == DataTypes.FixMap.GetHighBits(4); + } + + /// + /// Stopping the collection of MessagePack token + /// + /// Array segment bytes protected abstract ArraySegment? StopTokenGathering(); + /// + /// Start the collection of MessagePack token + /// protected abstract void StartTokenGathering(); } } diff --git a/Shared/MessagePack/Stream/ByteArrayReader.cs b/Shared/MessagePack/Stream/ByteArrayReader.cs index 4a324fb..d784122 100644 --- a/Shared/MessagePack/Stream/ByteArrayReader.cs +++ b/Shared/MessagePack/Stream/ByteArrayReader.cs @@ -54,7 +54,7 @@ public override void Seek(long offset, SeekOrigin origin) #nullable enable protected override ArraySegment? StopTokenGathering() { - if ((_firstGatheredByte + 1) <= _data.Length) + if (_firstGatheredByte <= _data.Length) { return new ArraySegment(_data, (int)_firstGatheredByte, (int)(_offset - _firstGatheredByte)); } diff --git a/Shared/MessagePack/Stream/MemoryStreamReader.cs b/Shared/MessagePack/Stream/MemoryStreamReader.cs index 360a862..21952b8 100644 --- a/Shared/MessagePack/Stream/MemoryStreamReader.cs +++ b/Shared/MessagePack/Stream/MemoryStreamReader.cs @@ -12,6 +12,7 @@ namespace nanoFramework.MessagePack.Stream internal sealed class MemoryStreamReader : BaseReader, IDisposable { private readonly ArrayList _bytesGatheringBuffer = new(); + private long _bytesGatheringBufferLength = 0; private bool _bytesGatheringInProgress; @@ -33,7 +34,8 @@ public override byte ReadByte() var result = (byte)temp; if (_bytesGatheringInProgress) { - _bytesGatheringBuffer.Add(result); + _bytesGatheringBuffer.Add(new byte[] { result }); + _bytesGatheringBufferLength++; } return result; @@ -45,10 +47,8 @@ public override ArraySegment ReadBytes(uint length) if (_bytesGatheringInProgress) { - foreach (var b in buffer) - { - _bytesGatheringBuffer.Add(b); - } + _bytesGatheringBuffer.Add(buffer); + _bytesGatheringBufferLength += buffer.Length; } return buffer; @@ -59,10 +59,9 @@ public override void Seek(long offset, SeekOrigin origin) if (_bytesGatheringInProgress) { var buffer = ReadBytesInternal((uint)offset); - foreach (var b in buffer) - { - _bytesGatheringBuffer.Add(b); - } + + _bytesGatheringBuffer.Add(buffer); + _bytesGatheringBufferLength += buffer.Length; } else { @@ -75,7 +74,7 @@ public void Dispose() _stream.Dispose(); } - private ArraySegment ReadBytesInternal(uint length) + private byte[] ReadBytesInternal(uint length) { var buffer = new byte[length]; var read = _stream.Read(buffer, 0, buffer.Length); @@ -84,16 +83,25 @@ private ArraySegment ReadBytesInternal(uint length) throw ExceptionUtility.NotEnoughBytes(read, buffer.Length); } - return new(buffer, 0, buffer.Length); + return buffer; } #nullable enable protected override ArraySegment? StopTokenGathering() { - if ((_stream.Position + 1) <= _stream.Length) + if (_stream.Position <= _stream.Length) { _bytesGatheringInProgress = false; - var result = _bytesGatheringBuffer.ToArray(typeof(byte[])); - return new ArraySegment((byte[])result, 0, result.Length); + + byte[] result = new byte[_bytesGatheringBufferLength]; + + int destinationOffset = 0; + foreach (byte[] part in _bytesGatheringBuffer) + { + Array.Copy(part, 0, result, destinationOffset, part.Length); + destinationOffset += part.Length; + } + + return new ArraySegment(result, 0, result.Length); } else { @@ -105,6 +113,7 @@ protected override void StartTokenGathering() { _bytesGatheringInProgress = true; _bytesGatheringBuffer.Clear(); + _bytesGatheringBufferLength = 0; } } } diff --git a/UnitTestShared/TestData/SecureMessageConverter.cs b/UnitTestShared/TestData/SecureMessageConverter.cs index b1b2be6..6f6cc46 100644 --- a/UnitTestShared/TestData/SecureMessageConverter.cs +++ b/UnitTestShared/TestData/SecureMessageConverter.cs @@ -16,10 +16,12 @@ public SecureMessage Read([NotNull] IMessagePackReader reader) { StringBuilder sb = new(); var length = reader.ReadArrayLength(); + var intConverter = ConverterContext.GetConverter(typeof(int)); for (int i = 0; i < length; i++) { - sb.Append(SharedWordDictionary.WordDictionary[i]); + int wordIndex = (int)intConverter.Read(reader)!; + sb.Append(SharedWordDictionary.WordDictionary[wordIndex]); sb.Append(' '); } if (sb.Length > 0) @@ -32,14 +34,15 @@ public void Write(SecureMessage value, [NotNull] IMessagePackWriter writer) { var messageWords = value.Message.Split(' '); - uint length = BitConverter.ToUInt32(BitConverter.GetBytes(messageWords.Length), 0); + uint length = (uint)messageWords.Length; writer.WriteArrayHeader(length); var intConverter = ConverterContext.GetConverter(typeof(int)); foreach (var word in messageWords) { - intConverter.Write(SharedWordDictionary.WordDictionary.IndexOf(word), writer); + int wordIndex = SharedWordDictionary.WordDictionary.IndexOf(word); + intConverter.Write(wordIndex, writer); } } diff --git a/UnitTestShared/TestData/SharedWordDictionary.cs b/UnitTestShared/TestData/SharedWordDictionary.cs index 7226c4b..7555abe 100644 --- a/UnitTestShared/TestData/SharedWordDictionary.cs +++ b/UnitTestShared/TestData/SharedWordDictionary.cs @@ -11,7 +11,7 @@ static SharedWordDictionary() { WordDictionary = new() { - "MessagePak", + "MessagePack", "Hello", "at", "nanoFramework!", diff --git a/UnitTestShared/UnitTests.cs b/UnitTestShared/UnitTests.cs index c67bedf..03156bd 100644 --- a/UnitTestShared/UnitTests.cs +++ b/UnitTestShared/UnitTests.cs @@ -8,6 +8,7 @@ using nanoFramework.MessagePack; using UnitTestShared.Helpers; using UnitTestShared.TestData; +using System.IO; #if NANOFRAMEWORK_1_0 using nanoFramework.TestFramework; #endif @@ -110,12 +111,27 @@ public void TestConverterContext() public void ProcessCustomObjectTest() { var test = TestsHelper.GetTestClassObject(); - var result = MessagePackSerializer.Serialize(test); - Debug.WriteLine($"Serialize byte size: {result.Length}"); - var testResult = (TestClass)MessagePackSerializer.Deserialize(typeof(TestClass), result)!; - Assert.IsNotNull(testResult); + var resultBytes = MessagePackSerializer.Serialize(test); + Debug.WriteLine($"Serialize byte size: {resultBytes.Length}"); + var testResult = (TestClass)MessagePackSerializer.Deserialize(typeof(TestClass), resultBytes)!; + Assert.IsNotNull(testResult); Assert.AreEqual(test, testResult); + + using MemoryStream ms = new(resultBytes); + + var msTestResult = (TestClass)MessagePackSerializer.Deserialize(typeof(TestClass), ms)!; + + Assert.IsNotNull(msTestResult); + Assert.AreEqual(testResult, msTestResult); + + using MemoryStream writeMemory = new(); + MessagePackSerializer.Serialize(msTestResult, writeMemory); + byte[] testBytes = writeMemory.ToArray(); + + Assert.AreNotEqual(resultBytes, testBytes); + Assert.IsTrue(resultBytes.ArrayEqual(testBytes)); + } [TestMethod] @@ -140,8 +156,150 @@ public void CustomConverterTest() var recipientSecureMessage = (SecureMessage)MessagePackSerializer.Deserialize(typeof(SecureMessage), buffer)!; Debug.WriteLine($"Message received:\n{recipientSecureMessage.Message}"); + + Assert.AreNotEqual(secureMessage, recipientSecureMessage); + + Assert.AreEqual(secureMessage.Message, recipientSecureMessage.Message); } - } + [TestMethod] + public void PrimitivesTest() + { + byte[] shortBytes = MessagePackSerializer.Serialize(short.MaxValue); + var shortValue = (short)MessagePackSerializer.Deserialize(typeof(short), shortBytes)!; + Assert.AreEqual(short.MaxValue, shortValue); + + byte[] ushortBytes = MessagePackSerializer.Serialize(ushort.MaxValue); + var ushortValue = (ushort)MessagePackSerializer.Deserialize(typeof(ushort), ushortBytes)!; + Assert.AreEqual(ushort.MaxValue, ushortValue); + + byte[] intBytes = MessagePackSerializer.Serialize(int.MaxValue); + var intValue = (int)MessagePackSerializer.Deserialize(typeof(int), intBytes)!; + Assert.AreEqual(int.MaxValue, intValue); + + byte[] uintBytes = MessagePackSerializer.Serialize(uint.MaxValue); + var uintValue = (uint)MessagePackSerializer.Deserialize(typeof(uint), uintBytes)!; + Assert.AreEqual(uint.MaxValue, uintValue); + + byte[] longBytes = MessagePackSerializer.Serialize(long.MaxValue); + var longValue = (long)MessagePackSerializer.Deserialize(typeof(long), longBytes)!; + Assert.AreEqual(long.MaxValue, longValue); + + byte[] ulongBytes = MessagePackSerializer.Serialize(ulong.MaxValue); + var ulongValue = (ulong)MessagePackSerializer.Deserialize(typeof(ulong), ulongBytes)!; + Assert.AreEqual(ulong.MaxValue, ulongValue); + + byte[] byteBytes = MessagePackSerializer.Serialize(byte.MaxValue); + var byteValue = (byte)MessagePackSerializer.Deserialize(typeof(byte), byteBytes)!; + Assert.AreEqual(byte.MaxValue, byteValue); + + byte[] sbyteBytes = MessagePackSerializer.Serialize(sbyte.MaxValue); + var sbyteValue = (sbyte)MessagePackSerializer.Deserialize(typeof(sbyte), sbyteBytes)!; + Assert.AreEqual(sbyte.MaxValue, sbyteValue); + byte[] floatBytes = MessagePackSerializer.Serialize(float.MaxValue); + var floatValue = (float)MessagePackSerializer.Deserialize(typeof(float), floatBytes)!; + Assert.AreEqual(float.MaxValue, floatValue); + + byte[] doubleBytes = MessagePackSerializer.Serialize(double.MaxValue); + var doubleValue = (double)MessagePackSerializer.Deserialize(typeof(double), doubleBytes)!; + Assert.AreEqual(double.MaxValue, doubleValue); + + byte[] boolBytes = MessagePackSerializer.Serialize(true); + var boolValue = (bool)MessagePackSerializer.Deserialize(typeof(bool), boolBytes)!; + Assert.AreEqual(true, boolValue); + + boolBytes = MessagePackSerializer.Serialize(false); + boolValue = (bool)MessagePackSerializer.Deserialize(typeof(bool), boolBytes)!; + Assert.AreEqual(false, boolValue); + + byte[] charBytes = MessagePackSerializer.Serialize(char.MaxValue); + var charValue = (char)MessagePackSerializer.Deserialize(typeof(char), charBytes)!; + Assert.AreEqual(char.MaxValue, charValue); + + string testString = "I'm a UnitTest string!"; + byte[] stringBytes = MessagePackSerializer.Serialize(testString); + var stringValue = (string)MessagePackSerializer.Deserialize(typeof(string), stringBytes)!; + Assert.AreEqual(testString, stringValue); + + DateTime testDateTime = DateTime.UtcNow - TimeSpan.FromHours(1); + byte[] dateTimeBytes = MessagePackSerializer.Serialize(testDateTime); + var dateTimeValue = (DateTime)MessagePackSerializer.Deserialize(typeof(DateTime), dateTimeBytes)!; + Assert.AreEqual(testDateTime, dateTimeValue); + + byte[] timeSpanBytes = MessagePackSerializer.Serialize(TimeSpan.MaxValue); + var timeSpanValue = (TimeSpan)MessagePackSerializer.Deserialize(typeof(TimeSpan), timeSpanBytes)!; + Assert.AreEqual(TimeSpan.MaxValue, timeSpanValue); + + var testGuid = Guid.NewGuid(); + byte[] guidBytes = MessagePackSerializer.Serialize(testGuid); + var guidValue = (Guid)MessagePackSerializer.Deserialize(typeof(Guid), guidBytes)!; + Assert.AreEqual(testGuid, guidValue); + + } + + [TestMethod] + public void ArrayAndHashtableTest() + { + int[] intArray = new int[10] + { + int.MaxValue, + int.MaxValue / 2, + int.MaxValue / 3, + int.MaxValue - 100, + -236499102, + int.MinValue, + -3, + -98747483, + 239390494, + 1 + }; + + var arrayBytes = MessagePackSerializer.Serialize(intArray); + var intArrayValue = (int[])MessagePackSerializer.Deserialize(typeof(int[]), arrayBytes)!; + Assert.IsTrue(intArray.ArrayEqual(intArrayValue)); + + byte[] byteArray = new byte[10] + { + 100, + 111, + byte.MaxValue, + 126, + 45, + 20, + byte.MinValue, + 2, + 1, + 10 + }; + + arrayBytes = MessagePackSerializer.Serialize(byteArray); + var byteArrayValue = (byte[])MessagePackSerializer.Deserialize(typeof(byte[]), arrayBytes)!; + Assert.IsTrue(byteArray.ArrayEqual(byteArrayValue)); + + long[][] twoDimensionalArray = new long[][] + { + new long[]{1, 2, 3, 4, 5}, + new long[]{long.MaxValue -1, -1, -3985948353983, -8923879}, + new long[]{8734832748327, -84393275329, 87348932758, long.MinValue}, + }; + arrayBytes = MessagePackSerializer.Serialize(twoDimensionalArray); + var twoDimensionalArrayValue = (long[][])MessagePackSerializer.Deserialize(typeof(long[][]), arrayBytes)!; + Assert.IsTrue(twoDimensionalArray.ArrayEqual(twoDimensionalArrayValue)); + + Hashtable testHashtable = new() + { + { "gender", "Male" }, + { "snow", "white" }, + { Guid.NewGuid().ToString(), "nanoFramework.MessagePack" } + }; + arrayBytes = MessagePackSerializer.Serialize(testHashtable); + var hashtableValue = (Hashtable)MessagePackSerializer.Deserialize(typeof(Hashtable), arrayBytes)!; + Assert.AreEqual(testHashtable.Count, hashtableValue.Count); + foreach(DictionaryEntry entry in testHashtable) + { + Assert.AreEqual(entry.Value, hashtableValue[entry.Key]); + } + } + } } From f3ffc08b0b4f5d354695da0e0f56eaa3f46f5a6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Tue, 22 Apr 2025 01:28:19 +0100 Subject: [PATCH 2/5] dummy change --- Shared/MessagePack/ConverterContext.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Shared/MessagePack/ConverterContext.cs b/Shared/MessagePack/ConverterContext.cs index 387bedd..c4f5f38 100644 --- a/Shared/MessagePack/ConverterContext.cs +++ b/Shared/MessagePack/ConverterContext.cs @@ -402,3 +402,4 @@ private static DateTime ReadDateTimeExt(DataTypes type, IMessagePackReader reade } } } + From a0305dae305365c7b075ff73a172ac8eb7c2bfcc 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, 22 Apr 2025 13:20:34 +0400 Subject: [PATCH 3/5] Fix UnitTest --- UnitTestShared/Helpers/TestsHelper.cs | 45 +++++++++++++++++++++++++++ UnitTestShared/UnitTests.cs | 2 +- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/UnitTestShared/Helpers/TestsHelper.cs b/UnitTestShared/Helpers/TestsHelper.cs index 8c71b25..9e3315e 100644 --- a/UnitTestShared/Helpers/TestsHelper.cs +++ b/UnitTestShared/Helpers/TestsHelper.cs @@ -3,6 +3,7 @@ using System; using System.Collections; +using System.Text; using UnitTestShared.TestData; namespace UnitTestShared.Helpers @@ -159,5 +160,49 @@ internal static bool DictionaryEqual(this IDictionary? array1, IDictionary? arra return false; } + + internal static bool CheckTwoDimensionalLongArray(this long[][] source, long[][] destination, out string errorMessage) + { + errorMessage = string.Empty; + + if (source.Length != destination.Length) + { + errorMessage = $"Source array length {source.Length} not equal destination array length {destination.Length}"; + return false; + } + for(int y = 0; y < source.Length; y++) + { + if (source[y].Length != destination[y].Length) + { + errorMessage = $"Source array item index {y} length {source.Length} not equal destination array item index {y} length {destination.Length}"; + return false; + } + else + { + if(!source[y].ArrayEqual(destination[y])) + { + errorMessage = $"Source array item index {y} not equal destination array item index {y}\nSource array items:\n{source[y].JoinToString(", ")}\nDestination array items:\n{destination[y].JoinToString(", ")}"; + return false; + } + + } + } + + return true; + } + + internal static string JoinToString(this long[] objects, string joinString) + { + StringBuilder sb = new(); + foreach (long b in objects) + { + sb.Append(b.ToString()); + sb.Append(joinString); + } + if (sb.Length > 0) + sb.Remove(sb.Length - joinString.Length, joinString.Length); + + return sb.ToString(); + } } } diff --git a/UnitTestShared/UnitTests.cs b/UnitTestShared/UnitTests.cs index 03156bd..c2dd11f 100644 --- a/UnitTestShared/UnitTests.cs +++ b/UnitTestShared/UnitTests.cs @@ -285,7 +285,7 @@ public void ArrayAndHashtableTest() }; arrayBytes = MessagePackSerializer.Serialize(twoDimensionalArray); var twoDimensionalArrayValue = (long[][])MessagePackSerializer.Deserialize(typeof(long[][]), arrayBytes)!; - Assert.IsTrue(twoDimensionalArray.ArrayEqual(twoDimensionalArrayValue)); + Assert.IsTrue(twoDimensionalArray.CheckTwoDimensionalLongArray(twoDimensionalArrayValue, out string errorMessage), errorMessage); Hashtable testHashtable = new() { From 4fc01dc8d3ac37b47f74643b082a9e03e5ca5309 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, 22 Apr 2025 18:19:23 +0400 Subject: [PATCH 4/5] =?UTF-8?q?=D0=A1ode=20review=20by=20PR?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Shared/MessagePack/ConverterContext.cs | 57 +++++------ .../MessagePack/Converters/StringConverter.cs | 14 +-- Shared/MessagePack/Dto/ArraySegment.cs | 97 +++++++++++-------- Shared/MessagePack/MessagePackSerializer.cs | 49 +++++----- Shared/MessagePack/Stream/BaseReader.cs | 62 ++++++------ Shared/MessagePack/Stream/ByteArrayReader.cs | 30 +++--- .../MessagePack/Stream/IMessagePackReader.cs | 2 +- .../MessagePack/Stream/MemoryStreamReader.cs | 8 +- 8 files changed, 165 insertions(+), 154 deletions(-) diff --git a/Shared/MessagePack/ConverterContext.cs b/Shared/MessagePack/ConverterContext.cs index c4f5f38..2611326 100644 --- a/Shared/MessagePack/ConverterContext.cs +++ b/Shared/MessagePack/ConverterContext.cs @@ -22,22 +22,22 @@ namespace nanoFramework.MessagePack /// public static class ConverterContext { - private static readonly Type[] _emptyTypes = new Type[0]; + 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 _mappingDictionary = new(); + private static readonly Hashtable s_mappingDictionary = new(); #else - private static readonly ConcurrentDictionary _mappingDictionary = new(); + private static readonly ConcurrentDictionary s_mappingDictionary = new(); #endif - private static readonly Hashtable ConversionTable = new() + private static readonly Hashtable s_conversionTable = new() { { typeof(IDictionary).FullName!, s_mapConverter }, { typeof(Hashtable).FullName!, s_mapConverter }, - { typeof(ArrayList).FullName!, new ArrayListConverter()}, + { typeof(ArrayList).FullName!, new ArrayListConverter() }, { typeof(short).FullName!, new ShortConverter() }, { typeof(ushort).FullName!, new UshortConverter() }, { typeof(int).FullName!, new IntConverter() }, @@ -46,7 +46,7 @@ public static class ConverterContext { typeof(ulong).FullName!, new UlongConverter() }, { typeof(byte).FullName!, new ByteConverter() }, { typeof(sbyte).FullName!, new SbyteConverter() }, - { typeof(float).FullName!, new FloatConverter()}, + { typeof(float).FullName!, new FloatConverter() }, { typeof(double).FullName!, new DoubleConverter() }, { typeof(bool).FullName!, new BoolConverter() }, { typeof(string).FullName!, new StringConverter() }, @@ -55,10 +55,10 @@ public static class ConverterContext { 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(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)) }, @@ -73,7 +73,7 @@ public static class ConverterContext }; /// - /// Null value converter + /// Null value converter. /// public static IConverter NullConverter => s_nullConverter; @@ -81,16 +81,17 @@ public static class ConverterContext /// Adds new converter to collection to support more types. /// /// Type of object. - /// Converter instance which will be used to convert + /// 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)) { - throw new NotSupportedException($"Converter by type {type.Name} not support in convertors table."); + throw new NotSupportedException(); } - ConversionTable.Add(type.FullName!, converter); + s_conversionTable.Add(type.FullName!, converter); } /// @@ -99,14 +100,14 @@ public static void Add(Type type, IConverter converter) /// Type of object. public static void Remove(Type type) { - ConversionTable.Remove(type.FullName!); + s_conversionTable.Remove(type.FullName!); } /// /// Remove and then adds converter for given type. /// /// Type of object. - /// Converter instance which will be used to convert + /// Converter instance which will be used to convert . [MethodImpl(MethodImplOptions.Synchronized)] public static void Replace(Type type, IConverter converter) { @@ -115,10 +116,11 @@ public static void Replace(Type type, IConverter converter) } /// - /// Return converter by type + /// Return converter by type. /// - /// Type from converter - /// Converter interface + /// Type object from converter. + /// Converter interface or null. + /// If object type is . public static IConverter GetConverter(Type type) { if (type == typeof(object)) @@ -126,9 +128,9 @@ public static IConverter GetConverter(Type type) throw ExceptionUtility.ConverterNotFound(type); } - if (ConversionTable.Contains(type.FullName!)) + if (s_conversionTable.Contains(type.FullName!)) { - return (IConverter)ConversionTable[type.FullName!]!; + return (IConverter)s_conversionTable[type.FullName!]!; } return null!; @@ -200,18 +202,18 @@ internal static void SetMappingsValues(Type targetType, object targetObject, Has internal static object CreateInstance(Type targetType) { - var constructor = targetType.GetConstructor(_emptyTypes) ?? throw new Exception($"Target type {targetType?.FullName} does not have a parameterless constructor"); + var constructor = targetType.GetConstructor(s_emptyTypes) ?? throw new Exception($"Target type {targetType?.FullName} does not have a parameterless constructor"); return constructor.Invoke(null); } internal static MemberMapping[] GetMemberMapping(Type targetType) { #if NANOFRAMEWORK_1_0 - var cached = _mappingDictionary[targetType]; + var cached = s_mappingDictionary[targetType]; if (cached is not MemberMapping[] memberMappings) { #else - if (!_mappingDictionary.TryGetValue(targetType, out var memberMappings)) + if (!s_mappingDictionary.TryGetValue(targetType, out var memberMappings)) { #endif var mappings = new ArrayList(); @@ -222,9 +224,9 @@ internal static MemberMapping[] GetMemberMapping(Type targetType) memberMappings = (MemberMapping[])mappings.ToArray(typeof(MemberMapping)); #if NANOFRAMEWORK_1_0 - ThreadSafeAddItemCache(_mappingDictionary, targetType, memberMappings); + ThreadSafeAddItemCache(s_mappingDictionary, targetType, memberMappings); #else - _mappingDictionary.TryAdd(targetType, memberMappings); + s_mappingDictionary.TryAdd(targetType, memberMappings); #endif } @@ -316,7 +318,7 @@ private static void ThreadSafeAddItemCache(Hashtable hashtable, object key, obje { if (!hashtable.Contains(key)) { - lock(_mappingDictionary) + lock(s_mappingDictionary) { try { @@ -402,4 +404,3 @@ private static DateTime ReadDateTimeExt(DataTypes type, IMessagePackReader reade } } } - diff --git a/Shared/MessagePack/Converters/StringConverter.cs b/Shared/MessagePack/Converters/StringConverter.cs index 0de9b93..01cef5b 100644 --- a/Shared/MessagePack/Converters/StringConverter.cs +++ b/Shared/MessagePack/Converters/StringConverter.cs @@ -29,27 +29,24 @@ private static void Write(string value, IMessagePackWriter writer) writer.Write(data); } } - - private static string Read(IMessagePackReader reader) +#nullable enable + private static string? Read(IMessagePackReader reader) { - var type = reader.ReadDataType(); + DataTypes type = reader.ReadDataType(); switch (type) { case DataTypes.Null: - return null!; - + return null; case DataTypes.Str8: return ReadString(reader, NumberConverterHelper.ReadUInt8(reader)); - case DataTypes.Str16: return ReadString(reader, NumberConverterHelper.ReadUInt16(reader)); - case DataTypes.Str32: return ReadString(reader, NumberConverterHelper.ReadUInt32(reader)); } - if (TryGetFixStrLength(type, out var length)) + if (TryGetFixStrLength(type, out uint length)) { return ReadString(reader, length); } @@ -62,7 +59,6 @@ internal static string ReadString(IMessagePackReader reader, uint length) ArraySegment arraySegment = reader.ReadBytes(length); return Utf8.GetString(arraySegment.SourceBuffer, (int)arraySegment.SourceOffset + arraySegment.Position, (int)arraySegment.Length); - } private static bool TryGetFixStrLength(DataTypes type, out uint length) diff --git a/Shared/MessagePack/Dto/ArraySegment.cs b/Shared/MessagePack/Dto/ArraySegment.cs index 337ae28..152fad1 100644 --- a/Shared/MessagePack/Dto/ArraySegment.cs +++ b/Shared/MessagePack/Dto/ArraySegment.cs @@ -1,12 +1,12 @@ // 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; +using System.IO; using nanoFramework.MessagePack.Stream; using nanoFramework.MessagePack.Utility; -using System.IO; -using System; -using System.Diagnostics; namespace nanoFramework.MessagePack.Dto { @@ -15,16 +15,17 @@ namespace nanoFramework.MessagePack.Dto /// public class ArraySegment : BaseReader, IEnumerable { - private int _firstGatheredByte; private readonly byte[] _buffer; private readonly long _offset; private readonly long _length; + private int _firstGatheredByte; + /// - /// Gets byte by array segment + /// Gets byte by array segment. /// - /// The byte index in the array segment - /// Byte value + /// The byte index in the array segment. + /// Byte value. public byte this[int index] { get @@ -34,7 +35,9 @@ public byte this[int index] } internal byte[] SourceBuffer => _buffer; + internal long SourceOffset => _offset; + internal long Length => _length; /// @@ -42,6 +45,24 @@ public byte this[int index] /// public int Position { get; private set; } = 0; + /// + /// Implicit conversion from byte array to . + /// + /// Source byte array. + public static implicit operator ArraySegment(byte[] bytes) + { + return new ArraySegment(bytes, 0, bytes.Length); + } + + /// + /// Implicit conversion from to byte array. + /// + /// Source . + public static explicit operator byte[](ArraySegment segment) + { + return segment.ToArray(); + } + /// /// Initializes a new instance of the class. /// @@ -56,10 +77,10 @@ public ArraySegment(byte[] buffer, long offset, long length) } /// - /// Reads bytes in an array segment + /// Reads bytes in an array segment. /// - /// Required reading length - /// Segment by byte to current segment + /// Required reading length. + /// Segment by byte to current segment. public override ArraySegment ReadBytes(uint length) { var segment = new ArraySegment(_buffer, _offset + Position, length); @@ -68,23 +89,30 @@ public override ArraySegment ReadBytes(uint length) } /// - /// Move the reading position in the array segment + /// Move the reading position in the array segment. /// - /// Offset in bytes - /// Offset reference point - /// + /// Offset in bytes. + /// Offset reference point. + /// Unknown value. public override void Seek(long offset, SeekOrigin origin) { - Position = origin switch + switch (origin) { - SeekOrigin.Begin => (int)(offset), - SeekOrigin.Current => (int)(Position + offset), - SeekOrigin.End => (int)(_length + offset), - _ => throw new ArgumentOutOfRangeException(nameof(origin), origin.ToString()), - }; + case SeekOrigin.Begin: + Position = (int)offset; + break; + case SeekOrigin.Current: + Position = (int)(Position + offset); + break; + case SeekOrigin.End: + Position = (int)(_length + offset); + break; + default: + throw new ArgumentOutOfRangeException(); + } } - /// . + /// /// Read one byte from the segment. /// /// The byte read. @@ -103,24 +131,6 @@ public override byte ReadByte() return _buffer[_offset + Position++]; } - /// - /// Implicit conversion from byte array to . - /// - /// Source byte array. - public static implicit operator ArraySegment(byte[] bytes) - { - return new ArraySegment(bytes, 0, bytes.Length); - } - - /// - /// Implicit conversion from to byte array. - /// - /// Source . - public static explicit operator byte[](ArraySegment segment) - { - return segment.ToArray(); - } - /// /// Get bytes enumerator. /// @@ -139,9 +149,9 @@ private byte[] ToArray() } /// - /// Stopping the collection of MessagePack token in + /// Stopping the collection of MessagePack token in . /// - /// Array segment bytes + /// Array segment bytes . #nullable enable protected override ArraySegment? StopTokenGathering() { @@ -159,7 +169,7 @@ private byte[] ToArray() } /// - /// Start the collection of MessagePack token in + /// Start the collection of MessagePack token in . /// protected override void StartTokenGathering() { @@ -167,7 +177,7 @@ protected override void StartTokenGathering() } /// - /// Enumerator in an array segment + /// Enumerator in an array segment. /// public class ArraySegmentEnumerator : IEnumerator { @@ -178,6 +188,7 @@ internal ArraySegmentEnumerator(ArraySegment arraySegment) { _arraySegment = arraySegment; } + /// /// Gets the element corresponding to the current position in the segment. /// diff --git a/Shared/MessagePack/MessagePackSerializer.cs b/Shared/MessagePack/MessagePackSerializer.cs index 9876044..cc5c035 100644 --- a/Shared/MessagePack/MessagePackSerializer.cs +++ b/Shared/MessagePack/MessagePackSerializer.cs @@ -13,25 +13,28 @@ namespace nanoFramework.MessagePack public static class MessagePackSerializer { /// - /// Serialize object in to MessagePack byte array + /// Serialize object in to MessagePack byte array. /// - /// Source object - /// MessagePack byte array + /// Source object. + /// MessagePack byte array. public static byte[] Serialize(object data) { - var memoryStream = new MemoryStream(); - using var writer = new MemoryStreamWriter(memoryStream); - - Serialize(data, writer); + using (var memoryStream = new MemoryStream()) + { + using (var writer = new MemoryStreamWriter(memoryStream)) + { + Serialize(data, writer); - return memoryStream.ToArray(); + return memoryStream.ToArray(); + } + } } /// - /// Serialize object in to MessagePack stream + /// Serialize object in to MessagePack stream. /// - /// Source object - /// Target MessagePack stream + /// Source object. + /// Target MessagePack stream. public static void Serialize(object data, MemoryStream stream) { var writer = new MemoryStreamWriter(stream); @@ -39,11 +42,11 @@ public static void Serialize(object data, MemoryStream stream) } /// - /// Deserialize MessagePack data in to object + /// Deserialize MessagePack data in to object. /// - /// Target object type - /// MessagePack byte array data - /// Target object + /// Target object type. + /// MessagePack byte array data. + /// An instance of an target object after deserialization or . #nullable enable public static object? Deserialize(Type type, byte[] data) { @@ -52,16 +55,17 @@ public static void Serialize(object data, MemoryStream stream) } /// - /// Deserialize MessagePack data from stream in to object + /// Deserialize MessagePack data from stream in to object. /// - /// Target object type - /// MessagePack data stream - /// + /// Target object type. + /// MessagePack data stream. + /// An instance of an target object after deserialization or . public static object? Deserialize(Type type, MemoryStream stream) { - using var reader = new MemoryStreamReader(stream); - return Deserialize(type, reader); - + using (var reader = new MemoryStreamReader(stream)) + { + return Deserialize(type, reader); + } } private static object? Deserialize(Type type, IMessagePackReader reader) @@ -92,6 +96,5 @@ private static void Serialize(object data, IMessagePackWriter writer) ConverterContext.SerializeObject(type, data, writer); } } - } } diff --git a/Shared/MessagePack/Stream/BaseReader.cs b/Shared/MessagePack/Stream/BaseReader.cs index 26fe017..feea42f 100644 --- a/Shared/MessagePack/Stream/BaseReader.cs +++ b/Shared/MessagePack/Stream/BaseReader.cs @@ -9,34 +9,35 @@ namespace nanoFramework.MessagePack.Stream { /// - /// Base class for MessagePack reader + /// Base class for MessagePack reader. /// public abstract class BaseReader : IMessagePackReader { /// - /// Read byte from MessagePack + /// Read byte from MessagePack. /// - /// Reading byte + /// Read a byte. public abstract byte ReadByte(); /// - /// Read bytes from MessagePack + /// Read bytes from MessagePack. /// - /// Length to read - /// Reading bytes + /// Length to read. + /// with the bytes read. public abstract ArraySegment ReadBytes(uint length); /// - /// Moving the current read position in the array + /// Moving the current read position in the array. /// - /// Offset in bytes - /// Offset reference point + /// Offset in bytes. + /// Offset reference point. public abstract void Seek(long offset, SeekOrigin origin); /// - /// Read length MessagePack array + /// Read length MessagePack array. + /// The MessagePacket array type can be or or . /// - /// Length MessagePack array + /// Length MessagePack array by read for type array . public uint ReadArrayLength() { var type = ReadDataType(); @@ -60,9 +61,10 @@ public uint ReadArrayLength() } /// - /// Read length MessagePack map + /// Read length MessagePack map. + /// The MessagePacket map type can be or or . /// - /// Count elements in map + /// Count elements in map by read for type map . public uint ReadMapLength() { var type = ReadDataType(); @@ -87,18 +89,18 @@ public uint ReadMapLength() } /// - /// Read length MessagePack data type + /// Read MessagePack data type . /// - /// MessagePack data type + /// MessagePack data type . public virtual DataTypes ReadDataType() { return (DataTypes)ReadByte(); } /// - /// Skip MessagePack item in byte array + /// Skip MessagePack item in byte array. /// - /// + /// Unknown value. public void SkipToken() { var dataType = ReadDataType(); @@ -188,9 +190,9 @@ public void SkipToken() #nullable enable /// - /// Read MessagePack item in byte array + /// Read MessagePack item in byte array. /// - /// Array segment contained MessagePack item bytes + /// contained MessagePack item bytes. public ArraySegment? ReadToken() { StartTokenGathering(); @@ -230,11 +232,11 @@ private void SkipBytes(uint bytesCount) } /// - /// Try getting length fixed MessagePack Array + /// Try getting length fixed MessagePack array. /// - /// MessagePack Array type - /// Out length MessagePack Array - /// True if luck otherwise false + /// MessagePack array type . + /// Out length MessagePack array. + /// if luck otherwise . protected static bool TryGetLengthFromFixArray(DataTypes type, out uint length) { length = type - DataTypes.FixArray; @@ -242,11 +244,11 @@ protected static bool TryGetLengthFromFixArray(DataTypes type, out uint length) } /// - /// Try getting length fixed MessagePack Map + /// Try getting length fixed MessagePack map. /// - /// MessagePack Map type - /// Out length MessagePack Map - /// True if luck otherwise false + /// MessagePack map type . + /// Out length MessagePack map. + /// if luck otherwise . protected static bool TryGetLengthFromFixMap(DataTypes type, out uint length) { length = type - DataTypes.FixMap; @@ -254,13 +256,13 @@ protected static bool TryGetLengthFromFixMap(DataTypes type, out uint length) } /// - /// Stopping the collection of MessagePack token + /// Stopping the collection of MessagePack token. /// - /// Array segment bytes + /// bytes. protected abstract ArraySegment? StopTokenGathering(); /// - /// Start the collection of MessagePack token + /// Start the collection of MessagePack token. /// protected abstract void StartTokenGathering(); } diff --git a/Shared/MessagePack/Stream/ByteArrayReader.cs b/Shared/MessagePack/Stream/ByteArrayReader.cs index d784122..656d7e3 100644 --- a/Shared/MessagePack/Stream/ByteArrayReader.cs +++ b/Shared/MessagePack/Stream/ByteArrayReader.cs @@ -9,9 +9,9 @@ namespace nanoFramework.MessagePack.Stream { internal class ByteArrayReader : BaseReader { - private uint _firstGatheredByte; private readonly byte[] _data; + private uint _firstGatheredByte; private uint _offset; public ByteArrayReader(byte[] data) @@ -27,15 +27,6 @@ public override byte ReadByte() public override ArraySegment ReadBytes(uint length) { - //uint i = 0; - //byte[] arraySegment = new byte[length]; - //while(i < length) - //{ - // arraySegment[i] = _data[_offset++]; - // i++; - //} - //return arraySegment; - var segment = new ArraySegment(_data, _offset, length); _offset += length; return segment; @@ -43,13 +34,20 @@ public override ArraySegment ReadBytes(uint length) public override void Seek(long offset, SeekOrigin origin) { - _offset = origin switch + switch (origin) { - SeekOrigin.Begin => (uint)offset, - SeekOrigin.Current => (uint)(_offset + offset), - SeekOrigin.End => (uint)(_data.Length + offset), - _ => throw new ArgumentOutOfRangeException(nameof(origin), origin.ToString()), - }; + case SeekOrigin.Begin: + _offset = (uint)offset; + break; + case SeekOrigin.Current: + _offset = (uint)(_offset + offset); + break; + case SeekOrigin.End: + _offset = (uint)(_data.Length + offset); + break; + default: + throw new ArgumentOutOfRangeException(); + } } #nullable enable protected override ArraySegment? StopTokenGathering() diff --git a/Shared/MessagePack/Stream/IMessagePackReader.cs b/Shared/MessagePack/Stream/IMessagePackReader.cs index 34e2b32..efc1a02 100644 --- a/Shared/MessagePack/Stream/IMessagePackReader.cs +++ b/Shared/MessagePack/Stream/IMessagePackReader.cs @@ -49,7 +49,7 @@ public interface IMessagePackReader /// The length of the map. uint ReadMapLength(); - /// . + /// /// Skip item. /// void SkipToken(); diff --git a/Shared/MessagePack/Stream/MemoryStreamReader.cs b/Shared/MessagePack/Stream/MemoryStreamReader.cs index 21952b8..c20d38a 100644 --- a/Shared/MessagePack/Stream/MemoryStreamReader.cs +++ b/Shared/MessagePack/Stream/MemoryStreamReader.cs @@ -11,16 +11,16 @@ namespace nanoFramework.MessagePack.Stream { internal sealed class MemoryStreamReader : BaseReader, IDisposable { - private readonly ArrayList _bytesGatheringBuffer = new(); - private long _bytesGatheringBufferLength = 0; + private readonly MemoryStream _stream; + private readonly ArrayList _bytesGatheringBuffer; + private long _bytesGatheringBufferLength = 0; private bool _bytesGatheringInProgress; - private readonly MemoryStream _stream; - public MemoryStreamReader(MemoryStream stream) { _stream = stream; + _bytesGatheringBuffer = new ArrayList(); } public override byte ReadByte() From b3abb349d2aff95d674e45c925edbb8d00e71cb1 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, 22 Apr 2025 20:47:06 +0400 Subject: [PATCH 5/5] =?UTF-8?q?Fix=20=D1=81asting=20a=20signed=20num=20typ?= =?UTF-8?q?es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Extensions/NumberConverterHelper.cs | 26 +++++-------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/Shared/MessagePack/Extensions/NumberConverterHelper.cs b/Shared/MessagePack/Extensions/NumberConverterHelper.cs index f112459..1ff2983 100644 --- a/Shared/MessagePack/Extensions/NumberConverterHelper.cs +++ b/Shared/MessagePack/Extensions/NumberConverterHelper.cs @@ -43,7 +43,7 @@ internal static sbyte ReadInt8(IMessagePackReader reader) return (sbyte)temp; } - return (sbyte)(temp - byte.MaxValue - 1); + return (sbyte)((int)temp - byte.MaxValue - 1); } internal static byte ReadUInt8(IMessagePackReader reader) @@ -64,7 +64,7 @@ internal static short ReadInt16(IMessagePackReader reader) return (short)temp; } - return (short)(temp - 1 - ushort.MaxValue); + return (short)((int)temp - 1 - ushort.MaxValue); } internal static int ReadInt32(IMessagePackReader reader) @@ -75,7 +75,7 @@ internal static int ReadInt32(IMessagePackReader reader) return (int)temp; } - return (int)(temp - 1 - uint.MaxValue); + return (int)((long)temp - 1 - uint.MaxValue); } internal static uint ReadUInt32(IMessagePackReader reader) @@ -189,11 +189,9 @@ internal static bool TryGetInt32(DataTypes type, IMessagePackReader reader, out case DataTypes.UInt8: result = ReadUInt8(reader); return true; - case DataTypes.UInt16: result = ReadUInt16(reader); return true; - case DataTypes.UInt32: var uintValue = ReadUInt32(reader); @@ -204,19 +202,15 @@ internal static bool TryGetInt32(DataTypes type, IMessagePackReader reader, out } return false; - case DataTypes.Int8: result = ReadInt8(reader); return true; - case DataTypes.Int16: result = ReadInt16(reader); return true; - case DataTypes.Int32: result = ReadInt32(reader); return true; - default: return false; } @@ -242,42 +236,36 @@ internal static bool TryGetInt64(DataTypes type, IMessagePackReader reader, out case DataTypes.UInt8: result = ReadUInt8(reader); return true; - case DataTypes.UInt16: result = ReadUInt16(reader); return true; - case DataTypes.UInt32: result = ReadUInt32(reader); return true; - case DataTypes.UInt64: var ulongValue = ReadUInt64(reader); - if (ulongValue <= long.MaxValue) { result = (long)ulongValue; return true; } - - return false; + else + { + return false; + } case DataTypes.Int8: result = ReadInt8(reader); return true; - case DataTypes.Int16: result = ReadInt16(reader); return true; - case DataTypes.Int32: result = ReadInt32(reader); return true; - case DataTypes.Int64: result = reader.ReadInt64(); return true; - default: return false; }