diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2019-03-07 18:11:14 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-03-07 18:11:14 +0300 |
commit | 059ff6f99b5d9146e79fa6105272eb4e033efbf3 (patch) | |
tree | b779de4724efd4b3c4313e2041c4f091cf047c91 | |
parent | 82b6cda1716549b0e88ac0507c14d94508137ceb (diff) | |
parent | a849607880c28815f71839a11235aad798c04646 (diff) |
Merge pull request #27 from AArnott/fix9v2.0.46-alpha
Add support for IBufferWriter<byte>
28 files changed, 1735 insertions, 2603 deletions
diff --git a/sandbox/DynamicCodeDumper/DynamicCodeDumper.csproj b/sandbox/DynamicCodeDumper/DynamicCodeDumper.csproj index 3f8ef273..11b08573 100644 --- a/sandbox/DynamicCodeDumper/DynamicCodeDumper.csproj +++ b/sandbox/DynamicCodeDumper/DynamicCodeDumper.csproj @@ -10,6 +10,9 @@ <Compile Include="..\..\src\MessagePack\FloatBits.cs"> <Link>Code\FloatBits.cs</Link> </Compile> + <Compile Include="..\..\src\MessagePack\BufferWriter.cs"> + <Link>Code\BufferWriter.cs</Link> + </Compile> <Compile Include="..\..\src\MessagePack\Formatters\IMessagePackFormatter.cs"> <Link>Code\IMessagePackFormatter.cs</Link> </Compile> @@ -58,9 +61,6 @@ <Compile Include="..\..\src\MessagePack\Internal\UnsafeMemory.Low.cs"> <Link>Code\UnsafeMemory.Low.cs</Link> </Compile> - <Compile Include="..\..\src\MessagePack\MessagePackBinary.cs"> - <Link>Code\MessagePackBinary.cs</Link> - </Compile> <Compile Include="..\..\src\MessagePack\ExtensionHeader.cs"> <Link>Code\ExtensionHeader.cs</Link> </Compile> diff --git a/sandbox/DynamicCodeDumper/Program.cs b/sandbox/DynamicCodeDumper/Program.cs index 9fb98433..3ea196bd 100644 --- a/sandbox/DynamicCodeDumper/Program.cs +++ b/sandbox/DynamicCodeDumper/Program.cs @@ -60,9 +60,12 @@ namespace DynamicCodeDumper //DynamicContractlessObjectResolver.Instance.GetFormatter<EntityBase>(); - var sequenceWriter = new MessagePackWriter(); - f.Serialize(ref sequenceWriter, new MyClass { MyProperty1 = 100, MyProperty2 = "foo" }, null); - sequenceWriter.Flush(); + using (var sequence = new Sequence<byte>()) + { + var sequenceWriter = new MessagePackWriter(sequence); + f.Serialize(ref sequenceWriter, new MyClass { MyProperty1 = 100, MyProperty2 = "foo" }, null); + sequenceWriter.Flush(); + } } catch (Exception ex) { diff --git a/sandbox/PerfBenchmarkDotNet/MessagePackWriterBenchmark.cs b/sandbox/PerfBenchmarkDotNet/MessagePackWriterBenchmark.cs index 5fedead6..3345fac0 100644 --- a/sandbox/PerfBenchmarkDotNet/MessagePackWriterBenchmark.cs +++ b/sandbox/PerfBenchmarkDotNet/MessagePackWriterBenchmark.cs @@ -12,6 +12,7 @@ namespace PerfBenchmarkDotNet public class MessagePackWriterBenchmark { private const int RepsOverArray = 300 * 1024; + private readonly Sequence<byte> sequence = new Sequence<byte>(); private readonly int[] values = new int[newmsgpack::MessagePack.MessagePackCode.MaxFixInt]; private readonly byte[] byteValues = new byte[newmsgpack::MessagePack.MessagePackCode.MaxFixInt]; @@ -34,11 +35,17 @@ namespace PerfBenchmarkDotNet } } + [IterationSetup] + public void IterationSetup() => this.sequence.GetSpan(bytes.Length); + + [IterationCleanup] + public void IterationCleanup() => this.sequence.Reset(); + [Benchmark(OperationsPerInvoke = RepsOverArray * newmsgpack::MessagePack.MessagePackCode.MaxFixInt)] [BenchmarkCategory("2.0")] public void Write_Byte() { - var writer = new newmsgpack::MessagePack.MessagePackWriter(this.bytes); + var writer = new newmsgpack::MessagePack.MessagePackWriter(this.sequence); for (int j = 0; j < RepsOverArray; j++) { for (int i = 0; i < byteValues.Length; i++) @@ -66,7 +73,7 @@ namespace PerfBenchmarkDotNet [BenchmarkCategory("2.0")] public void Write_UInt32() { - var writer = new newmsgpack::MessagePack.MessagePackWriter(this.bytes); + var writer = new newmsgpack::MessagePack.MessagePackWriter(this.sequence); for (int j = 0; j < RepsOverArray; j++) { for (int i = 0; i < values.Length; i++) @@ -80,7 +87,7 @@ namespace PerfBenchmarkDotNet [BenchmarkCategory("2.0")] public void Write_Int32() { - var writer = new newmsgpack::MessagePack.MessagePackWriter(this.bytes); + var writer = new newmsgpack::MessagePack.MessagePackWriter(this.sequence); for (int j = 0; j < RepsOverArray; j++) { for (int i = 0; i < values.Length; i++) @@ -110,12 +117,14 @@ namespace PerfBenchmarkDotNet { for (int j = 0; j < 5; j++) { - var writer = new newmsgpack::MessagePack.MessagePackWriter(this.bytes); + var writer = new newmsgpack::MessagePack.MessagePackWriter(this.sequence); for (int i = 0; i < 1000000; i++) { writer.Write("Hello!"); } writer.Flush(); + this.sequence.Reset(); + this.sequence.GetSpan(bytes.Length); } } diff --git a/sandbox/PerfBenchmarkDotNet/PerfBenchmarkDotNet.csproj b/sandbox/PerfBenchmarkDotNet/PerfBenchmarkDotNet.csproj index 1ec7105e..a727c4c1 100644 --- a/sandbox/PerfBenchmarkDotNet/PerfBenchmarkDotNet.csproj +++ b/sandbox/PerfBenchmarkDotNet/PerfBenchmarkDotNet.csproj @@ -2,6 +2,7 @@ <PropertyGroup> <OutputType>Exe</OutputType> <TargetFrameworks>net47;netcoreapp2.0</TargetFrameworks> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> </PropertyGroup> <ItemGroup> diff --git a/sandbox/PerfBenchmarkDotNet/Program.cs b/sandbox/PerfBenchmarkDotNet/Program.cs index f611fc6a..b51d63fe 100644 --- a/sandbox/PerfBenchmarkDotNet/Program.cs +++ b/sandbox/PerfBenchmarkDotNet/Program.cs @@ -53,6 +53,7 @@ namespace PerfBenchmarkDotNet typeof(ImproveStringKeySerializeBenchmark), typeof(MessagePackReaderBenchmark), typeof(MessagePackWriterBenchmark), + typeof(SpanBenchmarks), }); // args = new[] { "0" }; diff --git a/sandbox/PerfBenchmarkDotNet/SpanBenchmarks.cs b/sandbox/PerfBenchmarkDotNet/SpanBenchmarks.cs new file mode 100644 index 00000000..51529767 --- /dev/null +++ b/sandbox/PerfBenchmarkDotNet/SpanBenchmarks.cs @@ -0,0 +1,83 @@ +using System; +using System.Runtime.InteropServices; +using BenchmarkDotNet.Attributes; + +namespace PerfBenchmarkDotNet +{ + public class SpanBenchmarks + { + private const string SomeString = "Hi there"; + private static readonly byte[] byteArray = new byte[1]; + + [Benchmark] + public unsafe void PinString() + { + fixed (char* pChars = SomeString) + { + char ch = pChars[0]; + } + } + + [Benchmark] + public unsafe void GetSpanFromString() + { + char ch = SomeString.AsSpan()[0]; + } + + [Benchmark] + public unsafe void PinArray() + { + fixed (byte* pBytes = byteArray) + { + pBytes[0] = 7; + } + } + + [Benchmark] + public unsafe void PinArray_Indexer() + { + fixed (byte* pBytes = &byteArray[0]) + { + pBytes[0] = 7; + } + } + + [Benchmark] + public unsafe void PinSpan_GetReference() + { + Span<byte> span = byteArray; + fixed (byte* pBytes = &MemoryMarshal.GetReference(span)) + { + pBytes[0] = 7; + } + } + + [Benchmark] + public void PinSpan() + { + PinSpan_Helper(byteArray); + } + + private static unsafe void PinSpan_Helper(Span<byte> bytes) + { + fixed (byte* pBytes = bytes) + { + pBytes[0] = 7; + } + } + + [Benchmark] + public void PinSpan_Indexer() + { + PinSpan_Indexer_Helper(byteArray); + } + + private static unsafe void PinSpan_Indexer_Helper(Span<byte> bytes) + { + fixed (byte* pBytes = &bytes[0]) + { + pBytes[0] = 8; + } + } + } +} diff --git a/src/MessagePack/BufferWriter.cs b/src/MessagePack/BufferWriter.cs new file mode 100644 index 00000000..3ebf7c1f --- /dev/null +++ b/src/MessagePack/BufferWriter.cs @@ -0,0 +1,192 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) Andrew Arnott. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Buffers; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace MessagePack +{ + /// <summary> + /// A fast access struct that wraps <see cref="IBufferWriter{T}"/>. + /// </summary> + internal ref struct BufferWriter + { + /// <summary> + /// The underlying <see cref="IBufferWriter{T}"/>. + /// </summary> + private IBufferWriter<byte> _output; + + /// <summary> + /// The result of the last call to <see cref="IBufferWriter{T}.GetSpan(int)"/>, less any bytes already "consumed" with <see cref="Advance(int)"/>. + /// Backing field for the <see cref="Span"/> property. + /// </summary> + private Span<byte> _span; + + /// <summary> + /// The result of the last call to <see cref="IBufferWriter{T}.GetMemory(int)"/>, less any bytes already "consumed" with <see cref="Advance(int)"/>. + /// </summary> + private ArraySegment<byte> _segment; + + /// <summary> + /// The number of uncommitted bytes (all the calls to <see cref="Advance(int)"/> since the last call to <see cref="Commit"/>). + /// </summary> + private int _buffered; + + /// <summary> + /// The total number of bytes written with this writer. + /// Backing field for the <see cref="BytesCommitted"/> property. + /// </summary> + private long _bytesCommitted; + + /// <summary> + /// Initializes a new instance of the <see cref="BufferWriter"/> struct. + /// </summary> + /// <param name="output">The <see cref="IBufferWriter{T}"/> to be wrapped.</param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public BufferWriter(IBufferWriter<byte> output) + { + _buffered = 0; + _bytesCommitted = 0; + _output = output; + + var memory = _output.GetMemory(); + MemoryMarshal.TryGetArray(memory, out _segment); + _span = memory.Span; + } + + /// <summary> + /// Gets the result of the last call to <see cref="IBufferWriter{T}.GetSpan(int)"/>. + /// </summary> + public Span<byte> Span => _span; + + /// <summary> + /// Gets the total number of bytes written with this writer. + /// </summary> + public long BytesCommitted => _bytesCommitted; + + /// <summary> + /// Gets the <see cref="IBufferWriter{T}"/> underlying this instance. + /// </summary> + internal IBufferWriter<byte> UnderlyingWriter => _output; + + public Span<byte> GetSpan(int sizeHint) + { + Ensure(sizeHint); + return this.Span; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ref byte GetPointer(int sizeHint) + { + Ensure(sizeHint); + + if (_segment.Array != null) + { + return ref _segment.Array[_segment.Offset + _buffered]; + } + else + { + return ref _span.GetPinnableReference(); + } + } + + /// <summary> + /// Calls <see cref="IBufferWriter{T}.Advance(int)"/> on the underlying writer + /// with the number of uncommitted bytes. + /// </summary> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Commit() + { + var buffered = _buffered; + if (buffered > 0) + { + _bytesCommitted += buffered; + _buffered = 0; + _output.Advance(buffered); + _span = default; + } + } + + /// <summary> + /// Used to indicate that part of the buffer has been written to. + /// </summary> + /// <param name="count">The number of bytes written to.</param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Advance(int count) + { + _buffered += count; + _span = _span.Slice(count); + } + + /// <summary> + /// Copies the caller's buffer into this writer and calls <see cref="Advance(int)"/> with the length of the source buffer. + /// </summary> + /// <param name="source">The buffer to copy in.</param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ReadOnlySpan<byte> source) + { + if (_span.Length >= source.Length) + { + source.CopyTo(_span); + Advance(source.Length); + } + else + { + WriteMultiBuffer(source); + } + } + + /// <summary> + /// Acquires a new buffer if necessary to ensure that some given number of bytes can be written to a single buffer. + /// </summary> + /// <param name="count">The number of bytes that must be allocated in a single buffer.</param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Ensure(int count = 1) + { + if (_span.Length < count) + { + EnsureMore(count); + } + } + + /// <summary> + /// Gets a fresh span to write to, with an optional minimum size. + /// </summary> + /// <param name="count">The minimum size for the next requested buffer.</param> + [MethodImpl(MethodImplOptions.NoInlining)] + private void EnsureMore(int count = 0) + { + if (_buffered > 0) + { + Commit(); + } + + var memory = _output.GetMemory(count); + MemoryMarshal.TryGetArray(memory, out _segment); + _span = memory.Span; + } + + /// <summary> + /// Copies the caller's buffer into this writer, potentially across multiple buffers from the underlying writer. + /// </summary> + /// <param name="source">The buffer to copy into this writer.</param> + private void WriteMultiBuffer(ReadOnlySpan<byte> source) + { + while (source.Length > 0) + { + if (_span.Length == 0) + { + EnsureMore(); + } + + var writable = Math.Min(source.Length, _span.Length); + source.Slice(0, writable).CopyTo(_span); + source = source.Slice(writable); + Advance(writable); + } + } + } +} diff --git a/src/MessagePack/Formatters/CollectionFormatter.cs b/src/MessagePack/Formatters/CollectionFormatter.cs index ed73ccea..c8129489 100644 --- a/src/MessagePack/Formatters/CollectionFormatter.cs +++ b/src/MessagePack/Formatters/CollectionFormatter.cs @@ -228,29 +228,32 @@ namespace MessagePack.Formatters } else { - var scratchWriter = writer.Clone(); - var count = 0; - var e = GetSourceEnumerator(value); - try + using (var scratch = new Nerdbank.Streams.Sequence<byte>()) { - while (e.MoveNext()) + var scratchWriter = writer.Clone(scratch); + var count = 0; + var e = GetSourceEnumerator(value); + try { - count++; + while (e.MoveNext()) + { + count++; #if !UNITY - formatter.Serialize(ref scratchWriter, e.Current, resolver); + formatter.Serialize(ref scratchWriter, e.Current, resolver); #else - formatter.Serialize(ref scratchWriter, (TElement)e.Current, (IFormatterResolver)resolver); + formatter.Serialize(ref scratchWriter, (TElement)e.Current, (IFormatterResolver)resolver); #endif + } + } + finally + { + e.Dispose(); } - } - finally - { - e.Dispose(); - } - scratchWriter.Flush(); - writer.WriteArrayHeader(count); - writer.WriteRaw(scratchWriter.WrittenBytes); + scratchWriter.Flush(); + writer.WriteArrayHeader(count); + writer.WriteRaw(scratch.AsReadOnlySequence); + } } } } diff --git a/src/MessagePack/Formatters/TypelessFormatter.cs b/src/MessagePack/Formatters/TypelessFormatter.cs index dab01cac..a47325db 100644 --- a/src/MessagePack/Formatters/TypelessFormatter.cs +++ b/src/MessagePack/Formatters/TypelessFormatter.cs @@ -1,5 +1,6 @@ #if !UNITY +using MessagePack.Internal; using System; using System.Buffers; using System.Collections; @@ -9,7 +10,6 @@ using System.Linq.Expressions; using System.Reflection; using System.Runtime.InteropServices; using System.Text.RegularExpressions; -using MessagePack.Internal; namespace MessagePack.Formatters { @@ -197,13 +197,16 @@ namespace MessagePack.Formatters } // mark will be written at the end, when size is known - var scratchWriter = writer.Clone(); - scratchWriter.WriteString(typeName); - formatterAndDelegate.Value(formatterAndDelegate.Key, ref scratchWriter, value, resolver); - scratchWriter.Flush(); + using (var scratch = new Nerdbank.Streams.Sequence<byte>()) + { + var scratchWriter = writer.Clone(scratch); + scratchWriter.WriteString(typeName); + formatterAndDelegate.Value(formatterAndDelegate.Key, ref scratchWriter, value, resolver); + scratchWriter.Flush(); - // mark as extension with code 100 - writer.WriteExtensionFormat(new ExtensionResult((sbyte)TypelessFormatter.ExtensionTypeCode, scratchWriter.WrittenBytes)); + // mark as extension with code 100 + writer.WriteExtensionFormat(new ExtensionResult((sbyte)TypelessFormatter.ExtensionTypeCode, scratch.AsReadOnlySequence)); + } } public object Deserialize(ref MessagePackReader reader, IFormatterResolver resolver) @@ -308,10 +311,7 @@ namespace MessagePack.Formatters Expression body = deserialize; if (ti.IsValueType) - { body = Expression.Convert(deserialize, typeof(object)); - } - var lambda = Expression.Lambda<DeserializeMethod>(body, param0, param1, param2).Compile(); formatterAndDelegate = new KeyValuePair<object, DeserializeMethod>(formatter, lambda); diff --git a/src/MessagePack/LZ4/LZ4MessagePackSerializer.JSON.cs b/src/MessagePack/LZ4/LZ4MessagePackSerializer.JSON.cs index 2e8d03d0..8a89e090 100644 --- a/src/MessagePack/LZ4/LZ4MessagePackSerializer.JSON.cs +++ b/src/MessagePack/LZ4/LZ4MessagePackSerializer.JSON.cs @@ -29,10 +29,13 @@ namespace MessagePack /// </summary> public override void ConvertFromJson(TextReader reader, ref MessagePackWriter writer) { - var scratchWriter = writer.Clone(); - base.ConvertFromJson(reader, ref scratchWriter); - scratchWriter.Flush(); - ToLZ4BinaryCore(scratchWriter.WrittenBytes, ref writer); + using (var scratch = new Nerdbank.Streams.Sequence<byte>()) + { + var scratchWriter = writer.Clone(scratch); + base.ConvertFromJson(reader, ref scratchWriter); + scratchWriter.Flush(); + ToLZ4BinaryCore(scratch.AsReadOnlySequence, ref writer); + } } } } diff --git a/src/MessagePack/LZ4/LZ4MessagePackSerializer.cs b/src/MessagePack/LZ4/LZ4MessagePackSerializer.cs index 09c3d224..2feeee17 100644 --- a/src/MessagePack/LZ4/LZ4MessagePackSerializer.cs +++ b/src/MessagePack/LZ4/LZ4MessagePackSerializer.cs @@ -46,10 +46,13 @@ namespace MessagePack /// </summary> public override void Serialize<T>(ref MessagePackWriter writer, T value, IFormatterResolver resolver = null) { - var scratchWriter = writer.Clone(); - base.Serialize(ref scratchWriter, value, resolver); - scratchWriter.Flush(); - ToLZ4BinaryCore(scratchWriter.WrittenBytes, ref writer); + using (var scratch = new Nerdbank.Streams.Sequence<byte>()) + { + var scratchWriter = writer.Clone(scratch); + base.Serialize(ref scratchWriter, value, resolver); + scratchWriter.Flush(); + ToLZ4BinaryCore(scratch.AsReadOnlySequence, ref writer); + } } public override T Deserialize<T>(ref MessagePackReader reader, IFormatterResolver resolver = null) diff --git a/src/MessagePack/MessagePackBinary.cs b/src/MessagePack/MessagePackBinary.cs deleted file mode 100644 index 0da9b584..00000000 --- a/src/MessagePack/MessagePackBinary.cs +++ /dev/null @@ -1,2100 +0,0 @@ -using MessagePack.Internal; -using System; -using System.IO; - -namespace MessagePack -{ - /// <summary> - /// Encode/Decode Utility of MessagePack Spec. - /// https://github.com/msgpack/msgpack/blob/master/spec.md - /// </summary> - public static partial class MessagePackBinary - { - const int ArrayMaxSize = 0x7FFFFFC7; // https://msdn.microsoft.com/en-us/library/system.array - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static void EnsureCapacity(ref byte[] bytes, int offset, int appendLength) - { - var newLength = offset + appendLength; - - // If null(most case fisrt time) fill byte. - if (bytes == null) - { - bytes = new byte[newLength]; - return; - } - - // like MemoryStream.EnsureCapacity - var current = bytes.Length; - if (newLength > current) - { - int num = newLength; - if (num < 256) - { - num = 256; - FastResize(ref bytes, num); - return; - } - - if (current == ArrayMaxSize) - { - throw new InvalidOperationException("byte[] size reached maximum size of array(0x7FFFFFC7), can not write to single byte[]. Details: https://msdn.microsoft.com/en-us/library/system.array"); - } - - var newSize = unchecked((current * 2)); - if (newSize < 0) // overflow - { - num = ArrayMaxSize; - } - else - { - if (num < newSize) - { - num = newSize; - } - } - - FastResize(ref bytes, num); - } - } - - // Buffer.BlockCopy version of Array.Resize -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static void FastResize(ref byte[] array, int newSize) - { - if (newSize < 0) throw new ArgumentOutOfRangeException("newSize"); - - byte[] array2 = array; - if (array2 == null) - { - array = new byte[newSize]; - return; - } - - if (array2.Length != newSize) - { - byte[] array3 = new byte[newSize]; - Buffer.BlockCopy(array2, 0, array3, 0, (array2.Length > newSize) ? newSize : array2.Length); - array = array3; - } - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static byte[] FastCloneWithResize(byte[] array, int newSize) - { - if (newSize < 0) throw new ArgumentOutOfRangeException("newSize"); - - byte[] array2 = array; - if (array2 == null) - { - array = new byte[newSize]; - return array; - } - - byte[] array3 = new byte[newSize]; - Buffer.BlockCopy(array2, 0, array3, 0, (array2.Length > newSize) ? newSize : array2.Length); - return array3; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteNil(ref byte[] bytes, int offset) - { - EnsureCapacity(ref bytes, offset, 1); - - bytes[offset] = MessagePackCode.Nil; - return 1; - } - - /// <summary> - /// Unsafe. If value is guranteed 0 ~ MessagePackRange.MaxFixMapCount(15), can use this method. - /// </summary> - /// <returns></returns> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteFixedMapHeaderUnsafe(ref byte[] bytes, int offset, int count) - { - EnsureCapacity(ref bytes, offset, 1); - bytes[offset] = (byte)(MessagePackCode.MinFixMap | count); - return 1; - } - - /// <summary> - /// Write map count. - /// </summary> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteMapHeader(ref byte[] bytes, int offset, int count) - { - checked - { - return WriteMapHeader(ref bytes, offset, (uint)count); - } - } - - /// <summary> - /// Write map count. - /// </summary> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteMapHeader(ref byte[] bytes, int offset, uint count) - { - if (count <= MessagePackRange.MaxFixMapCount) - { - EnsureCapacity(ref bytes, offset, 1); - bytes[offset] = (byte)(MessagePackCode.MinFixMap | count); - return 1; - } - else if (count <= ushort.MaxValue) - { - EnsureCapacity(ref bytes, offset, 3); - unchecked - { - bytes[offset] = MessagePackCode.Map16; - bytes[offset + 1] = (byte)(count >> 8); - bytes[offset + 2] = (byte)(count); - } - return 3; - } - else - { - EnsureCapacity(ref bytes, offset, 5); - unchecked - { - bytes[offset] = MessagePackCode.Map32; - bytes[offset + 1] = (byte)(count >> 24); - bytes[offset + 2] = (byte)(count >> 16); - bytes[offset + 3] = (byte)(count >> 8); - bytes[offset + 4] = (byte)(count); - } - return 5; - } - } - - /// <summary> - /// Write map format header, always use map32 format(length is fixed, 5). - /// </summary> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteMapHeaderForceMap32Block(ref byte[] bytes, int offset, uint count) - { - EnsureCapacity(ref bytes, offset, 5); - unchecked - { - bytes[offset] = MessagePackCode.Map32; - bytes[offset + 1] = (byte)(count >> 24); - bytes[offset + 2] = (byte)(count >> 16); - bytes[offset + 3] = (byte)(count >> 8); - bytes[offset + 4] = (byte)(count); - } - return 5; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int GetArrayHeaderLength(int count) - { - if (count <= MessagePackRange.MaxFixArrayCount) - { - return 1; - } - else if (count <= ushort.MaxValue) - { - return 3; - } - else - { - return 5; - } - } - - /// <summary> - /// Unsafe. If value is guranteed 0 ~ MessagePackRange.MaxFixArrayCount(15), can use this method. - /// </summary> - /// <returns></returns> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteFixedArrayHeaderUnsafe(ref byte[] bytes, int offset, int count) - { - EnsureCapacity(ref bytes, offset, 1); - bytes[offset] = (byte)(MessagePackCode.MinFixArray | count); - return 1; - } - - /// <summary> - /// Write array count. - /// </summary> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteArrayHeader(ref byte[] bytes, int offset, int count) - { - checked - { - return WriteArrayHeader(ref bytes, offset, (uint)count); - } - } - - /// <summary> - /// Write array count. - /// </summary> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteArrayHeader(ref byte[] bytes, int offset, uint count) - { - if (count <= MessagePackRange.MaxFixArrayCount) - { - EnsureCapacity(ref bytes, offset, 1); - bytes[offset] = (byte)(MessagePackCode.MinFixArray | count); - return 1; - } - else if (count <= ushort.MaxValue) - { - EnsureCapacity(ref bytes, offset, 3); - unchecked - { - bytes[offset] = MessagePackCode.Array16; - bytes[offset + 1] = (byte)(count >> 8); - bytes[offset + 2] = (byte)(count); - } - return 3; - } - else - { - EnsureCapacity(ref bytes, offset, 5); - unchecked - { - bytes[offset] = MessagePackCode.Array32; - bytes[offset + 1] = (byte)(count >> 24); - bytes[offset + 2] = (byte)(count >> 16); - bytes[offset + 3] = (byte)(count >> 8); - bytes[offset + 4] = (byte)(count); - } - return 5; - } - } - - /// <summary> - /// Write array format header, always use array32 format(length is fixed, 5). - /// </summary> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteArrayHeaderForceArray32Block(ref byte[] bytes, int offset, uint count) - { - EnsureCapacity(ref bytes, offset, 5); - unchecked - { - bytes[offset] = MessagePackCode.Array32; - bytes[offset + 1] = (byte)(count >> 24); - bytes[offset + 2] = (byte)(count >> 16); - bytes[offset + 3] = (byte)(count >> 8); - bytes[offset + 4] = (byte)(count); - } - return 5; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteBoolean(ref byte[] bytes, int offset, bool value) - { - EnsureCapacity(ref bytes, offset, 1); - - bytes[offset] = (value ? MessagePackCode.True : MessagePackCode.False); - return 1; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteByte(ref byte[] bytes, int offset, byte value) - { - if (value <= MessagePackCode.MaxFixInt) - { - EnsureCapacity(ref bytes, offset, 1); - bytes[offset] = value; - return 1; - } - else - { - EnsureCapacity(ref bytes, offset, 2); - bytes[offset] = MessagePackCode.UInt8; - bytes[offset + 1] = value; - return 2; - } - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteByteForceByteBlock(ref byte[] bytes, int offset, byte value) - { - EnsureCapacity(ref bytes, offset, 2); - bytes[offset] = MessagePackCode.UInt8; - bytes[offset + 1] = value; - return 2; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteBytes(ref byte[] bytes, int offset, byte[] value) - { - if (value == null) - { - return WriteNil(ref bytes, offset); - } - else - { - return WriteBytes(ref bytes, offset, value, 0, value.Length); - } - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteBytes(ref byte[] dest, int dstOffset, byte[] src, int srcOffset, int count) - { - if (src == null) - { - return WriteNil(ref dest, dstOffset); - } - - if (count <= byte.MaxValue) - { - var size = count + 2; - EnsureCapacity(ref dest, dstOffset, size); - - dest[dstOffset] = MessagePackCode.Bin8; - dest[dstOffset + 1] = (byte)count; - - Buffer.BlockCopy(src, srcOffset, dest, dstOffset + 2, count); - return size; - } - else if (count <= UInt16.MaxValue) - { - var size = count + 3; - EnsureCapacity(ref dest, dstOffset, size); - - unchecked - { - dest[dstOffset] = MessagePackCode.Bin16; - dest[dstOffset + 1] = (byte)(count >> 8); - dest[dstOffset + 2] = (byte)(count); - } - - Buffer.BlockCopy(src, srcOffset, dest, dstOffset + 3, count); - return size; - } - else - { - var size = count + 5; - EnsureCapacity(ref dest, dstOffset, size); - - unchecked - { - dest[dstOffset] = MessagePackCode.Bin32; - dest[dstOffset + 1] = (byte)(count >> 24); - dest[dstOffset + 2] = (byte)(count >> 16); - dest[dstOffset + 3] = (byte)(count >> 8); - dest[dstOffset + 4] = (byte)(count); - } - - Buffer.BlockCopy(src, srcOffset, dest, dstOffset + 5, count); - return size; - } - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteSByte(ref byte[] bytes, int offset, sbyte value) - { - if (value < MessagePackRange.MinFixNegativeInt) - { - EnsureCapacity(ref bytes, offset, 2); - bytes[offset] = MessagePackCode.Int8; - bytes[offset + 1] = unchecked((byte)(value)); - return 2; - } - else - { - EnsureCapacity(ref bytes, offset, 1); - bytes[offset] = unchecked((byte)value); - return 1; - } - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteSByteForceSByteBlock(ref byte[] bytes, int offset, sbyte value) - { - EnsureCapacity(ref bytes, offset, 2); - bytes[offset] = MessagePackCode.Int8; - bytes[offset + 1] = unchecked((byte)(value)); - return 2; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteSingle(ref byte[] bytes, int offset, float value) - { - EnsureCapacity(ref bytes, offset, 5); - - bytes[offset] = MessagePackCode.Float32; - - var num = new Float32Bits(value); - if (BitConverter.IsLittleEndian) - { - bytes[offset + 1] = num.Byte3; - bytes[offset + 2] = num.Byte2; - bytes[offset + 3] = num.Byte1; - bytes[offset + 4] = num.Byte0; - } - else - { - bytes[offset + 1] = num.Byte0; - bytes[offset + 2] = num.Byte1; - bytes[offset + 3] = num.Byte2; - bytes[offset + 4] = num.Byte3; - } - - return 5; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteDouble(ref byte[] bytes, int offset, double value) - { - EnsureCapacity(ref bytes, offset, 9); - - bytes[offset] = MessagePackCode.Float64; - - var num = new Float64Bits(value); - if (BitConverter.IsLittleEndian) - { - bytes[offset + 1] = num.Byte7; - bytes[offset + 2] = num.Byte6; - bytes[offset + 3] = num.Byte5; - bytes[offset + 4] = num.Byte4; - bytes[offset + 5] = num.Byte3; - bytes[offset + 6] = num.Byte2; - bytes[offset + 7] = num.Byte1; - bytes[offset + 8] = num.Byte0; - } - else - { - bytes[offset + 1] = num.Byte0; - bytes[offset + 2] = num.Byte1; - bytes[offset + 3] = num.Byte2; - bytes[offset + 4] = num.Byte3; - bytes[offset + 5] = num.Byte4; - bytes[offset + 6] = num.Byte5; - bytes[offset + 7] = num.Byte6; - bytes[offset + 8] = num.Byte7; - } - - return 9; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteInt16(ref byte[] bytes, int offset, short value) - { - if (value >= 0) - { - // positive int(use uint) - if (value <= MessagePackRange.MaxFixPositiveInt) - { - EnsureCapacity(ref bytes, offset, 1); - bytes[offset] = unchecked((byte)value); - return 1; - } - else if (value <= byte.MaxValue) - { - EnsureCapacity(ref bytes, offset, 2); - bytes[offset] = MessagePackCode.UInt8; - bytes[offset + 1] = unchecked((byte)value); - return 2; - } - else - { - EnsureCapacity(ref bytes, offset, 3); - bytes[offset] = MessagePackCode.UInt16; - bytes[offset + 1] = unchecked((byte)(value >> 8)); - bytes[offset + 2] = unchecked((byte)value); - return 3; - } - } - else - { - // negative int(use int) - if (MessagePackRange.MinFixNegativeInt <= value) - { - EnsureCapacity(ref bytes, offset, 1); - bytes[offset] = unchecked((byte)value); - return 1; - } - else if (sbyte.MinValue <= value) - { - EnsureCapacity(ref bytes, offset, 2); - bytes[offset] = MessagePackCode.Int8; - bytes[offset + 1] = unchecked((byte)value); - return 2; - } - else - { - EnsureCapacity(ref bytes, offset, 3); - bytes[offset] = MessagePackCode.Int16; - bytes[offset + 1] = unchecked((byte)(value >> 8)); - bytes[offset + 2] = unchecked((byte)value); - return 3; - } - } - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteInt16ForceInt16Block(ref byte[] bytes, int offset, short value) - { - EnsureCapacity(ref bytes, offset, 3); - bytes[offset] = MessagePackCode.Int16; - bytes[offset + 1] = unchecked((byte)(value >> 8)); - bytes[offset + 2] = unchecked((byte)value); - return 3; - } - - /// <summary> - /// Unsafe. If value is guranteed 0 ~ MessagePackCode.MaxFixInt(127), can use this method. - /// </summary> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WritePositiveFixedIntUnsafe(ref byte[] bytes, int offset, int value) - { - EnsureCapacity(ref bytes, offset, 1); - bytes[offset] = (byte)value; - return 1; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteInt32(ref byte[] bytes, int offset, int value) - { - if (value >= 0) - { - // positive int(use uint) - if (value <= MessagePackRange.MaxFixPositiveInt) - { - EnsureCapacity(ref bytes, offset, 1); - bytes[offset] = unchecked((byte)value); - return 1; - } - else if (value <= byte.MaxValue) - { - EnsureCapacity(ref bytes, offset, 2); - bytes[offset] = MessagePackCode.UInt8; - bytes[offset + 1] = unchecked((byte)value); - return 2; - } - else if (value <= ushort.MaxValue) - { - EnsureCapacity(ref bytes, offset, 3); - bytes[offset] = MessagePackCode.UInt16; - bytes[offset + 1] = unchecked((byte)(value >> 8)); - bytes[offset + 2] = unchecked((byte)value); - return 3; - } - else - { - EnsureCapacity(ref bytes, offset, 5); - bytes[offset] = MessagePackCode.UInt32; - bytes[offset + 1] = unchecked((byte)(value >> 24)); - bytes[offset + 2] = unchecked((byte)(value >> 16)); - bytes[offset + 3] = unchecked((byte)(value >> 8)); - bytes[offset + 4] = unchecked((byte)value); - return 5; - } - } - else - { - // negative int(use int) - if (MessagePackRange.MinFixNegativeInt <= value) - { - EnsureCapacity(ref bytes, offset, 1); - bytes[offset] = unchecked((byte)value); - return 1; - } - else if (sbyte.MinValue <= value) - { - EnsureCapacity(ref bytes, offset, 2); - bytes[offset] = MessagePackCode.Int8; - bytes[offset + 1] = unchecked((byte)value); - return 2; - } - else if (short.MinValue <= value) - { - EnsureCapacity(ref bytes, offset, 3); - bytes[offset] = MessagePackCode.Int16; - bytes[offset + 1] = unchecked((byte)(value >> 8)); - bytes[offset + 2] = unchecked((byte)value); - return 3; - } - else - { - EnsureCapacity(ref bytes, offset, 5); - bytes[offset] = MessagePackCode.Int32; - bytes[offset + 1] = unchecked((byte)(value >> 24)); - bytes[offset + 2] = unchecked((byte)(value >> 16)); - bytes[offset + 3] = unchecked((byte)(value >> 8)); - bytes[offset + 4] = unchecked((byte)value); - return 5; - } - } - } - - /// <summary> - /// Acquire static message block(always 5 bytes). - /// </summary> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteInt32ForceInt32Block(ref byte[] bytes, int offset, int value) - { - EnsureCapacity(ref bytes, offset, 5); - bytes[offset] = MessagePackCode.Int32; - bytes[offset + 1] = unchecked((byte)(value >> 24)); - bytes[offset + 2] = unchecked((byte)(value >> 16)); - bytes[offset + 3] = unchecked((byte)(value >> 8)); - bytes[offset + 4] = unchecked((byte)value); - return 5; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteInt64(ref byte[] bytes, int offset, long value) - { - if (value >= 0) - { - // positive int(use uint) - if (value <= MessagePackRange.MaxFixPositiveInt) - { - EnsureCapacity(ref bytes, offset, 1); - bytes[offset] = unchecked((byte)value); - return 1; - } - else if (value <= byte.MaxValue) - { - EnsureCapacity(ref bytes, offset, 2); - bytes[offset] = MessagePackCode.UInt8; - bytes[offset + 1] = unchecked((byte)value); - return 2; - } - else if (value <= ushort.MaxValue) - { - EnsureCapacity(ref bytes, offset, 3); - bytes[offset] = MessagePackCode.UInt16; - bytes[offset + 1] = unchecked((byte)(value >> 8)); - bytes[offset + 2] = unchecked((byte)value); - return 3; - } - else if (value <= uint.MaxValue) - { - EnsureCapacity(ref bytes, offset, 5); - bytes[offset] = MessagePackCode.UInt32; - bytes[offset + 1] = unchecked((byte)(value >> 24)); - bytes[offset + 2] = unchecked((byte)(value >> 16)); - bytes[offset + 3] = unchecked((byte)(value >> 8)); - bytes[offset + 4] = unchecked((byte)value); - return 5; - } - else - { - EnsureCapacity(ref bytes, offset, 9); - bytes[offset] = MessagePackCode.UInt64; - bytes[offset + 1] = unchecked((byte)(value >> 56)); - bytes[offset + 2] = unchecked((byte)(value >> 48)); - bytes[offset + 3] = unchecked((byte)(value >> 40)); - bytes[offset + 4] = unchecked((byte)(value >> 32)); - bytes[offset + 5] = unchecked((byte)(value >> 24)); - bytes[offset + 6] = unchecked((byte)(value >> 16)); - bytes[offset + 7] = unchecked((byte)(value >> 8)); - bytes[offset + 8] = unchecked((byte)value); - return 9; - } - } - else - { - // negative int(use int) - if (MessagePackRange.MinFixNegativeInt <= value) - { - EnsureCapacity(ref bytes, offset, 1); - bytes[offset] = unchecked((byte)value); - return 1; - } - else if (sbyte.MinValue <= value) - { - EnsureCapacity(ref bytes, offset, 2); - bytes[offset] = MessagePackCode.Int8; - bytes[offset + 1] = unchecked((byte)value); - return 2; - } - else if (short.MinValue <= value) - { - EnsureCapacity(ref bytes, offset, 3); - bytes[offset] = MessagePackCode.Int16; - bytes[offset + 1] = unchecked((byte)(value >> 8)); - bytes[offset + 2] = unchecked((byte)value); - return 3; - } - else if (int.MinValue <= value) - { - EnsureCapacity(ref bytes, offset, 5); - bytes[offset] = MessagePackCode.Int32; - bytes[offset + 1] = unchecked((byte)(value >> 24)); - bytes[offset + 2] = unchecked((byte)(value >> 16)); - bytes[offset + 3] = unchecked((byte)(value >> 8)); - bytes[offset + 4] = unchecked((byte)value); - return 5; - } - else - { - EnsureCapacity(ref bytes, offset, 9); - bytes[offset] = MessagePackCode.Int64; - bytes[offset + 1] = unchecked((byte)(value >> 56)); - bytes[offset + 2] = unchecked((byte)(value >> 48)); - bytes[offset + 3] = unchecked((byte)(value >> 40)); - bytes[offset + 4] = unchecked((byte)(value >> 32)); - bytes[offset + 5] = unchecked((byte)(value >> 24)); - bytes[offset + 6] = unchecked((byte)(value >> 16)); - bytes[offset + 7] = unchecked((byte)(value >> 8)); - bytes[offset + 8] = unchecked((byte)value); - return 9; - } - } - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteInt64ForceInt64Block(ref byte[] bytes, int offset, long value) - { - EnsureCapacity(ref bytes, offset, 9); - bytes[offset] = MessagePackCode.Int64; - bytes[offset + 1] = unchecked((byte)(value >> 56)); - bytes[offset + 2] = unchecked((byte)(value >> 48)); - bytes[offset + 3] = unchecked((byte)(value >> 40)); - bytes[offset + 4] = unchecked((byte)(value >> 32)); - bytes[offset + 5] = unchecked((byte)(value >> 24)); - bytes[offset + 6] = unchecked((byte)(value >> 16)); - bytes[offset + 7] = unchecked((byte)(value >> 8)); - bytes[offset + 8] = unchecked((byte)value); - return 9; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteUInt16(ref byte[] bytes, int offset, ushort value) - { - if (value <= MessagePackRange.MaxFixPositiveInt) - { - EnsureCapacity(ref bytes, offset, 1); - bytes[offset] = unchecked((byte)value); - return 1; - } - else if (value <= byte.MaxValue) - { - EnsureCapacity(ref bytes, offset, 2); - bytes[offset] = MessagePackCode.UInt8; - bytes[offset + 1] = unchecked((byte)value); - return 2; - } - else - { - EnsureCapacity(ref bytes, offset, 3); - bytes[offset] = MessagePackCode.UInt16; - bytes[offset + 1] = unchecked((byte)(value >> 8)); - bytes[offset + 2] = unchecked((byte)value); - return 3; - } - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteUInt16ForceUInt16Block(ref byte[] bytes, int offset, ushort value) - { - EnsureCapacity(ref bytes, offset, 3); - bytes[offset] = MessagePackCode.UInt16; - bytes[offset + 1] = unchecked((byte)(value >> 8)); - bytes[offset + 2] = unchecked((byte)value); - return 3; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteUInt32(ref byte[] bytes, int offset, uint value) - { - if (value <= MessagePackRange.MaxFixPositiveInt) - { - EnsureCapacity(ref bytes, offset, 1); - bytes[offset] = unchecked((byte)value); - return 1; - } - else if (value <= byte.MaxValue) - { - EnsureCapacity(ref bytes, offset, 2); - bytes[offset] = MessagePackCode.UInt8; - bytes[offset + 1] = unchecked((byte)value); - return 2; - } - else if (value <= ushort.MaxValue) - { - EnsureCapacity(ref bytes, offset, 3); - bytes[offset] = MessagePackCode.UInt16; - bytes[offset + 1] = unchecked((byte)(value >> 8)); - bytes[offset + 2] = unchecked((byte)value); - return 3; - } - else - { - EnsureCapacity(ref bytes, offset, 5); - bytes[offset] = MessagePackCode.UInt32; - bytes[offset + 1] = unchecked((byte)(value >> 24)); - bytes[offset + 2] = unchecked((byte)(value >> 16)); - bytes[offset + 3] = unchecked((byte)(value >> 8)); - bytes[offset + 4] = unchecked((byte)value); - return 5; - } - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteUInt32ForceUInt32Block(ref byte[] bytes, int offset, uint value) - { - EnsureCapacity(ref bytes, offset, 5); - bytes[offset] = MessagePackCode.UInt32; - bytes[offset + 1] = unchecked((byte)(value >> 24)); - bytes[offset + 2] = unchecked((byte)(value >> 16)); - bytes[offset + 3] = unchecked((byte)(value >> 8)); - bytes[offset + 4] = unchecked((byte)value); - return 5; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteUInt64(ref byte[] bytes, int offset, ulong value) - { - if (value <= MessagePackRange.MaxFixPositiveInt) - { - EnsureCapacity(ref bytes, offset, 1); - bytes[offset] = unchecked((byte)value); - return 1; - } - else if (value <= byte.MaxValue) - { - EnsureCapacity(ref bytes, offset, 2); - bytes[offset] = MessagePackCode.UInt8; - bytes[offset + 1] = unchecked((byte)value); - return 2; - } - else if (value <= ushort.MaxValue) - { - EnsureCapacity(ref bytes, offset, 3); - bytes[offset] = MessagePackCode.UInt16; - bytes[offset + 1] = unchecked((byte)(value >> 8)); - bytes[offset + 2] = unchecked((byte)value); - return 3; - } - else if (value <= uint.MaxValue) - { - EnsureCapacity(ref bytes, offset, 5); - bytes[offset] = MessagePackCode.UInt32; - bytes[offset + 1] = unchecked((byte)(value >> 24)); - bytes[offset + 2] = unchecked((byte)(value >> 16)); - bytes[offset + 3] = unchecked((byte)(value >> 8)); - bytes[offset + 4] = unchecked((byte)value); - return 5; - } - else - { - EnsureCapacity(ref bytes, offset, 9); - bytes[offset] = MessagePackCode.UInt64; - bytes[offset + 1] = unchecked((byte)(value >> 56)); - bytes[offset + 2] = unchecked((byte)(value >> 48)); - bytes[offset + 3] = unchecked((byte)(value >> 40)); - bytes[offset + 4] = unchecked((byte)(value >> 32)); - bytes[offset + 5] = unchecked((byte)(value >> 24)); - bytes[offset + 6] = unchecked((byte)(value >> 16)); - bytes[offset + 7] = unchecked((byte)(value >> 8)); - bytes[offset + 8] = unchecked((byte)value); - return 9; - } - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteUInt64ForceUInt64Block(ref byte[] bytes, int offset, ulong value) - { - EnsureCapacity(ref bytes, offset, 9); - bytes[offset] = MessagePackCode.UInt64; - bytes[offset + 1] = unchecked((byte)(value >> 56)); - bytes[offset + 2] = unchecked((byte)(value >> 48)); - bytes[offset + 3] = unchecked((byte)(value >> 40)); - bytes[offset + 4] = unchecked((byte)(value >> 32)); - bytes[offset + 5] = unchecked((byte)(value >> 24)); - bytes[offset + 6] = unchecked((byte)(value >> 16)); - bytes[offset + 7] = unchecked((byte)(value >> 8)); - bytes[offset + 8] = unchecked((byte)value); - return 9; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteChar(ref byte[] bytes, int offset, char value) - { - return WriteUInt16(ref bytes, offset, (ushort)value); - } - - /// <summary> - /// Unsafe. If value is guranteed length is 0 ~ 31, can use this method. - /// </summary> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteFixedStringUnsafe(ref byte[] bytes, int offset, string value, int byteCount) - { - EnsureCapacity(ref bytes, offset, byteCount + 1); - bytes[offset] = (byte)(MessagePackCode.MinFixStr | byteCount); - StringEncoding.UTF8.GetBytes(value, 0, value.Length, bytes, offset + 1); - - return byteCount + 1; - } - - /// <summary> - /// Unsafe. If pre-calculated byteCount of target string, can use this method. - /// </summary> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteStringUnsafe(ref byte[] bytes, int offset, string value, int byteCount) - { - if (byteCount <= MessagePackRange.MaxFixStringLength) - { - EnsureCapacity(ref bytes, offset, byteCount + 1); - bytes[offset] = (byte)(MessagePackCode.MinFixStr | byteCount); - StringEncoding.UTF8.GetBytes(value, 0, value.Length, bytes, offset + 1); - return byteCount + 1; - } - else if (byteCount <= byte.MaxValue) - { - EnsureCapacity(ref bytes, offset, byteCount + 2); - bytes[offset] = MessagePackCode.Str8; - bytes[offset + 1] = unchecked((byte)byteCount); - StringEncoding.UTF8.GetBytes(value, 0, value.Length, bytes, offset + 2); - return byteCount + 2; - } - else if (byteCount <= ushort.MaxValue) - { - EnsureCapacity(ref bytes, offset, byteCount + 3); - bytes[offset] = MessagePackCode.Str16; - bytes[offset + 1] = unchecked((byte)(byteCount >> 8)); - bytes[offset + 2] = unchecked((byte)byteCount); - StringEncoding.UTF8.GetBytes(value, 0, value.Length, bytes, offset + 3); - return byteCount + 3; - } - else - { - EnsureCapacity(ref bytes, offset, byteCount + 5); - bytes[offset] = MessagePackCode.Str32; - bytes[offset + 1] = unchecked((byte)(byteCount >> 24)); - bytes[offset + 2] = unchecked((byte)(byteCount >> 16)); - bytes[offset + 3] = unchecked((byte)(byteCount >> 8)); - bytes[offset + 4] = unchecked((byte)byteCount); - StringEncoding.UTF8.GetBytes(value, 0, value.Length, bytes, offset + 5); - return byteCount + 5; - } - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteStringBytes(ref byte[] bytes, int offset, byte[] utf8stringBytes) - { - var byteCount = utf8stringBytes.Length; - if (byteCount <= MessagePackRange.MaxFixStringLength) - { - EnsureCapacity(ref bytes, offset, byteCount + 1); - bytes[offset] = (byte)(MessagePackCode.MinFixStr | byteCount); - Buffer.BlockCopy(utf8stringBytes, 0, bytes, offset + 1, byteCount); - return byteCount + 1; - } - else if (byteCount <= byte.MaxValue) - { - EnsureCapacity(ref bytes, offset, byteCount + 2); - bytes[offset] = MessagePackCode.Str8; - bytes[offset + 1] = unchecked((byte)byteCount); - Buffer.BlockCopy(utf8stringBytes, 0, bytes, offset + 2, byteCount); - return byteCount + 2; - } - else if (byteCount <= ushort.MaxValue) - { - EnsureCapacity(ref bytes, offset, byteCount + 3); - bytes[offset] = MessagePackCode.Str16; - bytes[offset + 1] = unchecked((byte)(byteCount >> 8)); - bytes[offset + 2] = unchecked((byte)byteCount); - Buffer.BlockCopy(utf8stringBytes, 0, bytes, offset + 3, byteCount); - return byteCount + 3; - } - else - { - EnsureCapacity(ref bytes, offset, byteCount + 5); - bytes[offset] = MessagePackCode.Str32; - bytes[offset + 1] = unchecked((byte)(byteCount >> 24)); - bytes[offset + 2] = unchecked((byte)(byteCount >> 16)); - bytes[offset + 3] = unchecked((byte)(byteCount >> 8)); - bytes[offset + 4] = unchecked((byte)byteCount); - Buffer.BlockCopy(utf8stringBytes, 0, bytes, offset + 5, byteCount); - return byteCount + 5; - } - } - - public static byte[] GetEncodedStringBytes(string value) - { - var byteCount = StringEncoding.UTF8.GetByteCount(value); - if (byteCount <= MessagePackRange.MaxFixStringLength) - { - var bytes = new byte[byteCount + 1]; - bytes[0] = (byte)(MessagePackCode.MinFixStr | byteCount); - StringEncoding.UTF8.GetBytes(value, 0, value.Length, bytes, 1); - return bytes; - } - else if (byteCount <= byte.MaxValue) - { - var bytes = new byte[byteCount + 2]; - bytes[0] = MessagePackCode.Str8; - bytes[1] = unchecked((byte)byteCount); - StringEncoding.UTF8.GetBytes(value, 0, value.Length, bytes, 2); - return bytes; - } - else if (byteCount <= ushort.MaxValue) - { - var bytes = new byte[byteCount + 3]; - bytes[0] = MessagePackCode.Str16; - bytes[1] = unchecked((byte)(byteCount >> 8)); - bytes[2] = unchecked((byte)byteCount); - StringEncoding.UTF8.GetBytes(value, 0, value.Length, bytes, 3); - return bytes; - } - else - { - var bytes = new byte[byteCount + 5]; - bytes[0] = MessagePackCode.Str32; - bytes[1] = unchecked((byte)(byteCount >> 24)); - bytes[2] = unchecked((byte)(byteCount >> 16)); - bytes[3] = unchecked((byte)(byteCount >> 8)); - bytes[4] = unchecked((byte)byteCount); - StringEncoding.UTF8.GetBytes(value, 0, value.Length, bytes, 5); - return bytes; - } - } - - public static int WriteString(ref byte[] bytes, int offset, string value, bool oldSpec = false) - { - if (value == null) return WriteNil(ref bytes, offset); - - // MaxByteCount -> WritePrefix -> GetBytes has some overheads of `MaxByteCount` - // solves heuristic length check - - // ensure buffer by MaxByteCount(faster than GetByteCount) - MessagePackBinary.EnsureCapacity(ref bytes, offset, StringEncoding.UTF8.GetMaxByteCount(value.Length) + 5); - - int useOffset; - if (value.Length <= MessagePackRange.MaxFixStringLength) - { - useOffset = 1; - } - else if (value.Length <= byte.MaxValue && !oldSpec) - { - useOffset = 2; - } - else if (value.Length <= ushort.MaxValue) - { - useOffset = 3; - } - else - { - useOffset = 5; - } - - // skip length area - var writeBeginOffset = offset + useOffset; - var byteCount = StringEncoding.UTF8.GetBytes(value, 0, value.Length, bytes, writeBeginOffset); - - // move body and write prefix - if (byteCount <= MessagePackRange.MaxFixStringLength) - { - if (useOffset != 1) - { - Buffer.BlockCopy(bytes, writeBeginOffset, bytes, offset + 1, byteCount); - } - bytes[offset] = (byte)(MessagePackCode.MinFixStr | byteCount); - return byteCount + 1; - } - else if (byteCount <= byte.MaxValue && !oldSpec) - { - if (useOffset != 2) - { - Buffer.BlockCopy(bytes, writeBeginOffset, bytes, offset + 2, byteCount); - } - - bytes[offset] = MessagePackCode.Str8; - bytes[offset + 1] = unchecked((byte)byteCount); - return byteCount + 2; - } - else if (byteCount <= ushort.MaxValue) - { - if (useOffset != 3) - { - Buffer.BlockCopy(bytes, writeBeginOffset, bytes, offset + 3, byteCount); - } - - bytes[offset] = MessagePackCode.Str16; - bytes[offset + 1] = unchecked((byte)(byteCount >> 8)); - bytes[offset + 2] = unchecked((byte)byteCount); - return byteCount + 3; - } - else - { - if (useOffset != 5) - { - Buffer.BlockCopy(bytes, writeBeginOffset, bytes, offset + 5, byteCount); - } - - bytes[offset] = MessagePackCode.Str32; - bytes[offset + 1] = unchecked((byte)(byteCount >> 24)); - bytes[offset + 2] = unchecked((byte)(byteCount >> 16)); - bytes[offset + 3] = unchecked((byte)(byteCount >> 8)); - bytes[offset + 4] = unchecked((byte)byteCount); - return byteCount + 5; - } - } - - public static unsafe int WriteString(ref byte[] bytes, int offset, ReadOnlySpan<char> value, bool oldSpec = false) - { - if (value == null) return WriteNil(ref bytes, offset); - - // MaxByteCount -> WritePrefix -> GetBytes has some overheads of `MaxByteCount` - // solves heuristic length check - - // ensure buffer by MaxByteCount(faster than GetByteCount) - MessagePackBinary.EnsureCapacity(ref bytes, offset, StringEncoding.UTF8.GetMaxByteCount(value.Length) + 5); - - int useOffset; - if (value.Length <= MessagePackRange.MaxFixStringLength) - { - useOffset = 1; - } - else if (value.Length <= byte.MaxValue && !oldSpec) - { - useOffset = 2; - } - else if (value.Length <= ushort.MaxValue) - { - useOffset = 3; - } - else - { - useOffset = 5; - } - - // skip length area - var writeBeginOffset = offset + useOffset; - int byteCount; - fixed (char* pValue = value) - fixed (byte* pBytes = &bytes[writeBeginOffset]) - { - byteCount = StringEncoding.UTF8.GetBytes(pValue, value.Length, pBytes, bytes.Length - writeBeginOffset); - } - - // move body and write prefix - if (byteCount <= MessagePackRange.MaxFixStringLength) - { - if (useOffset != 1) - { - Buffer.BlockCopy(bytes, writeBeginOffset, bytes, offset + 1, byteCount); - } - bytes[offset] = (byte)(MessagePackCode.MinFixStr | byteCount); - return byteCount + 1; - } - else if (byteCount <= byte.MaxValue && !oldSpec) - { - if (useOffset != 2) - { - Buffer.BlockCopy(bytes, writeBeginOffset, bytes, offset + 2, byteCount); - } - - bytes[offset] = MessagePackCode.Str8; - bytes[offset + 1] = unchecked((byte)byteCount); - return byteCount + 2; - } - else if (byteCount <= ushort.MaxValue) - { - if (useOffset != 3) - { - Buffer.BlockCopy(bytes, writeBeginOffset, bytes, offset + 3, byteCount); - } - - bytes[offset] = MessagePackCode.Str16; - bytes[offset + 1] = unchecked((byte)(byteCount >> 8)); - bytes[offset + 2] = unchecked((byte)byteCount); - return byteCount + 3; - } - else - { - if (useOffset != 5) - { - Buffer.BlockCopy(bytes, writeBeginOffset, bytes, offset + 5, byteCount); - } - - bytes[offset] = MessagePackCode.Str32; - bytes[offset + 1] = unchecked((byte)(byteCount >> 24)); - bytes[offset + 2] = unchecked((byte)(byteCount >> 16)); - bytes[offset + 3] = unchecked((byte)(byteCount >> 8)); - bytes[offset + 4] = unchecked((byte)byteCount); - return byteCount + 5; - } - } - - public static int WriteStringForceStr32Block(ref byte[] bytes, int offset, string value) - { - if (value == null) return WriteNil(ref bytes, offset); - - MessagePackBinary.EnsureCapacity(ref bytes, offset, StringEncoding.UTF8.GetMaxByteCount(value.Length) + 5); - - var byteCount = StringEncoding.UTF8.GetBytes(value, 0, value.Length, bytes, offset + 5); - - bytes[offset] = MessagePackCode.Str32; - bytes[offset + 1] = unchecked((byte)(byteCount >> 24)); - bytes[offset + 2] = unchecked((byte)(byteCount >> 16)); - bytes[offset + 3] = unchecked((byte)(byteCount >> 8)); - bytes[offset + 4] = unchecked((byte)byteCount); - return byteCount + 5; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteExtensionFormatHeader(ref byte[] bytes, int offset, sbyte typeCode, int dataLength) - { - switch (dataLength) - { - case 1: - EnsureCapacity(ref bytes, offset, 3); - bytes[offset] = MessagePackCode.FixExt1; - bytes[offset + 1] = unchecked((byte)typeCode); - return 2; - case 2: - EnsureCapacity(ref bytes, offset, 4); - bytes[offset] = MessagePackCode.FixExt2; - bytes[offset + 1] = unchecked((byte)typeCode); - return 2; - case 4: - EnsureCapacity(ref bytes, offset, 6); - bytes[offset] = MessagePackCode.FixExt4; - bytes[offset + 1] = unchecked((byte)typeCode); - return 2; - case 8: - EnsureCapacity(ref bytes, offset, 10); - bytes[offset] = MessagePackCode.FixExt8; - bytes[offset + 1] = unchecked((byte)typeCode); - return 2; - case 16: - EnsureCapacity(ref bytes, offset, 18); - bytes[offset] = MessagePackCode.FixExt16; - bytes[offset + 1] = unchecked((byte)typeCode); - return 2; - default: - unchecked - { - if (dataLength <= byte.MaxValue) - { - EnsureCapacity(ref bytes, offset, dataLength + 3); - bytes[offset] = MessagePackCode.Ext8; - bytes[offset + 1] = unchecked((byte)(dataLength)); - bytes[offset + 2] = unchecked((byte)typeCode); - return 3; - } - else if (dataLength <= UInt16.MaxValue) - { - EnsureCapacity(ref bytes, offset, dataLength + 4); - bytes[offset] = MessagePackCode.Ext16; - bytes[offset + 1] = unchecked((byte)(dataLength >> 8)); - bytes[offset + 2] = unchecked((byte)(dataLength)); - bytes[offset + 3] = unchecked((byte)typeCode); - return 4; - } - else - { - EnsureCapacity(ref bytes, offset, dataLength + 6); - bytes[offset] = MessagePackCode.Ext32; - bytes[offset + 1] = unchecked((byte)(dataLength >> 24)); - bytes[offset + 2] = unchecked((byte)(dataLength >> 16)); - bytes[offset + 3] = unchecked((byte)(dataLength >> 8)); - bytes[offset + 4] = unchecked((byte)dataLength); - bytes[offset + 5] = unchecked((byte)typeCode); - return 6; - } - } - } - } - - /// <summary> - /// Write extension format header, always use ext32 format(length is fixed, 6). - /// </summary> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteExtensionFormatHeaderForceExt32Block(ref byte[] bytes, int offset, sbyte typeCode, int dataLength) - { - EnsureCapacity(ref bytes, offset, dataLength + 6); - bytes[offset] = MessagePackCode.Ext32; - bytes[offset + 1] = unchecked((byte)(dataLength >> 24)); - bytes[offset + 2] = unchecked((byte)(dataLength >> 16)); - bytes[offset + 3] = unchecked((byte)(dataLength >> 8)); - bytes[offset + 4] = unchecked((byte)dataLength); - bytes[offset + 5] = unchecked((byte)typeCode); - return 6; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteExtensionFormat(ref byte[] bytes, int offset, sbyte typeCode, byte[] data) - { - var length = data.Length; - switch (length) - { - case 1: - EnsureCapacity(ref bytes, offset, 3); - bytes[offset] = MessagePackCode.FixExt1; - bytes[offset + 1] = unchecked((byte)typeCode); - bytes[offset + 2] = data[0]; - return 3; - case 2: - EnsureCapacity(ref bytes, offset, 4); - bytes[offset] = MessagePackCode.FixExt2; - bytes[offset + 1] = unchecked((byte)typeCode); - bytes[offset + 2] = data[0]; - bytes[offset + 3] = data[1]; - return 4; - case 4: - EnsureCapacity(ref bytes, offset, 6); - bytes[offset] = MessagePackCode.FixExt4; - bytes[offset + 1] = unchecked((byte)typeCode); - bytes[offset + 2] = data[0]; - bytes[offset + 3] = data[1]; - bytes[offset + 4] = data[2]; - bytes[offset + 5] = data[3]; - return 6; - case 8: - EnsureCapacity(ref bytes, offset, 10); - bytes[offset] = MessagePackCode.FixExt8; - bytes[offset + 1] = unchecked((byte)typeCode); - bytes[offset + 2] = data[0]; - bytes[offset + 3] = data[1]; - bytes[offset + 4] = data[2]; - bytes[offset + 5] = data[3]; - bytes[offset + 6] = data[4]; - bytes[offset + 7] = data[5]; - bytes[offset + 8] = data[6]; - bytes[offset + 9] = data[7]; - return 10; - case 16: - EnsureCapacity(ref bytes, offset, 18); - bytes[offset] = MessagePackCode.FixExt16; - bytes[offset + 1] = unchecked((byte)typeCode); - bytes[offset + 2] = data[0]; - bytes[offset + 3] = data[1]; - bytes[offset + 4] = data[2]; - bytes[offset + 5] = data[3]; - bytes[offset + 6] = data[4]; - bytes[offset + 7] = data[5]; - bytes[offset + 8] = data[6]; - bytes[offset + 9] = data[7]; - bytes[offset + 10] = data[8]; - bytes[offset + 11] = data[9]; - bytes[offset + 12] = data[10]; - bytes[offset + 13] = data[11]; - bytes[offset + 14] = data[12]; - bytes[offset + 15] = data[13]; - bytes[offset + 16] = data[14]; - bytes[offset + 17] = data[15]; - return 18; - default: - unchecked - { - if (data.Length <= byte.MaxValue) - { - EnsureCapacity(ref bytes, offset, length + 3); - bytes[offset] = MessagePackCode.Ext8; - bytes[offset + 1] = unchecked((byte)(length)); - bytes[offset + 2] = unchecked((byte)typeCode); - Buffer.BlockCopy(data, 0, bytes, offset + 3, length); - return length + 3; - } - else if (data.Length <= UInt16.MaxValue) - { - EnsureCapacity(ref bytes, offset, length + 4); - bytes[offset] = MessagePackCode.Ext16; - bytes[offset + 1] = unchecked((byte)(length >> 8)); - bytes[offset + 2] = unchecked((byte)(length)); - bytes[offset + 3] = unchecked((byte)typeCode); - Buffer.BlockCopy(data, 0, bytes, offset + 4, length); - return length + 4; - } - else - { - EnsureCapacity(ref bytes, offset, length + 6); - bytes[offset] = MessagePackCode.Ext32; - bytes[offset + 1] = unchecked((byte)(length >> 24)); - bytes[offset + 2] = unchecked((byte)(length >> 16)); - bytes[offset + 3] = unchecked((byte)(length >> 8)); - bytes[offset + 4] = unchecked((byte)length); - bytes[offset + 5] = unchecked((byte)typeCode); - Buffer.BlockCopy(data, 0, bytes, offset + 6, length); - return length + 6; - } - } - } - } - - // Timestamp spec - // https://github.com/msgpack/msgpack/pull/209 - // FixExt4(-1) => seconds | [1970-01-01 00:00:00 UTC, 2106-02-07 06:28:16 UTC) range - // FixExt8(-1) => nanoseconds + seconds | [1970-01-01 00:00:00.000000000 UTC, 2514-05-30 01:53:04.000000000 UTC) range - // Ext8(12,-1) => nanoseconds + seconds | [-584554047284-02-23 16:59:44 UTC, 584554051223-11-09 07:00:16.000000000 UTC) range - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteDateTime(ref byte[] bytes, int offset, DateTime dateTime) - { - dateTime = dateTime.ToUniversalTime(); - - var secondsSinceBclEpoch = dateTime.Ticks / TimeSpan.TicksPerSecond; - var seconds = secondsSinceBclEpoch - DateTimeConstants.BclSecondsAtUnixEpoch; - var nanoseconds = (dateTime.Ticks % TimeSpan.TicksPerSecond) * DateTimeConstants.NanosecondsPerTick; - - // reference pseudo code. - /* - struct timespec { - long tv_sec; // seconds - long tv_nsec; // nanoseconds - } time; - if ((time.tv_sec >> 34) == 0) - { - uint64_t data64 = (time.tv_nsec << 34) | time.tv_sec; - if (data & 0xffffffff00000000L == 0) - { - // timestamp 32 - uint32_t data32 = data64; - serialize(0xd6, -1, data32) - } - else - { - // timestamp 64 - serialize(0xd7, -1, data64) - } - } - else - { - // timestamp 96 - serialize(0xc7, 12, -1, time.tv_nsec, time.tv_sec) - } - */ - - if ((seconds >> 34) == 0) - { - var data64 = unchecked((ulong)((nanoseconds << 34) | seconds)); - if ((data64 & 0xffffffff00000000L) == 0) - { - // timestamp 32(seconds in 32-bit unsigned int) - var data32 = (UInt32)data64; - EnsureCapacity(ref bytes, offset, 6); - bytes[offset] = MessagePackCode.FixExt4; - bytes[offset + 1] = unchecked((byte)ReservedMessagePackExtensionTypeCode.DateTime); - bytes[offset + 2] = unchecked((byte)(data32 >> 24)); - bytes[offset + 3] = unchecked((byte)(data32 >> 16)); - bytes[offset + 4] = unchecked((byte)(data32 >> 8)); - bytes[offset + 5] = unchecked((byte)data32); - return 6; - } - else - { - // timestamp 64(nanoseconds in 30-bit unsigned int | seconds in 34-bit unsigned int) - EnsureCapacity(ref bytes, offset, 10); - bytes[offset] = MessagePackCode.FixExt8; - bytes[offset + 1] = unchecked((byte)ReservedMessagePackExtensionTypeCode.DateTime); - bytes[offset + 2] = unchecked((byte)(data64 >> 56)); - bytes[offset + 3] = unchecked((byte)(data64 >> 48)); - bytes[offset + 4] = unchecked((byte)(data64 >> 40)); - bytes[offset + 5] = unchecked((byte)(data64 >> 32)); - bytes[offset + 6] = unchecked((byte)(data64 >> 24)); - bytes[offset + 7] = unchecked((byte)(data64 >> 16)); - bytes[offset + 8] = unchecked((byte)(data64 >> 8)); - bytes[offset + 9] = unchecked((byte)data64); - return 10; - } - } - else - { - // timestamp 96( nanoseconds in 32-bit unsigned int | seconds in 64-bit signed int ) - EnsureCapacity(ref bytes, offset, 15); - bytes[offset] = MessagePackCode.Ext8; - bytes[offset + 1] = (byte)12; - bytes[offset + 2] = unchecked((byte)ReservedMessagePackExtensionTypeCode.DateTime); - bytes[offset + 3] = unchecked((byte)(nanoseconds >> 24)); - bytes[offset + 4] = unchecked((byte)(nanoseconds >> 16)); - bytes[offset + 5] = unchecked((byte)(nanoseconds >> 8)); - bytes[offset + 6] = unchecked((byte)nanoseconds); - bytes[offset + 7] = unchecked((byte)(seconds >> 56)); - bytes[offset + 8] = unchecked((byte)(seconds >> 48)); - bytes[offset + 9] = unchecked((byte)(seconds >> 40)); - bytes[offset + 10] = unchecked((byte)(seconds >> 32)); - bytes[offset + 11] = unchecked((byte)(seconds >> 24)); - bytes[offset + 12] = unchecked((byte)(seconds >> 16)); - bytes[offset + 13] = unchecked((byte)(seconds >> 8)); - bytes[offset + 14] = unchecked((byte)seconds); - return 15; - } - } - } - - // Stream Overload - partial class MessagePackBinary - { - static class StreamDecodeMemoryPool - { - [ThreadStatic] - static byte[] buffer = null; - - public static byte[] GetBuffer() - { - if (buffer == null) - { - buffer = new byte[65536]; - } - return buffer; - } - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteNil(Stream stream) - { - stream.WriteByte(MessagePackCode.Nil); - return 1; - } - - /// <summary> - /// Unsafe. If value is guranteed 0 ~ MessagePackRange.MaxFixMapCount(15), can use this method. - /// </summary> - /// <returns></returns> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteFixedMapHeaderUnsafe(Stream stream, int count) - { - stream.WriteByte((byte)(MessagePackCode.MinFixMap | count)); - return 1; - } - - /// <summary> - /// Write map count. - /// </summary> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteMapHeader(Stream stream, int count) - { - checked - { - return WriteMapHeader(stream, (uint)count); - } - } - - /// <summary> - /// Write map count. - /// </summary> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteMapHeader(Stream stream, uint count) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteMapHeader(ref buffer, 0, count); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - - /// <summary> - /// Write map format header, always use map32 format(length is fixed, 5). - /// </summary> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteMapHeaderForceMap32Block(Stream stream, uint count) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteMapHeaderForceMap32Block(ref buffer, 0, count); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - - /// <summary> - /// Unsafe. If value is guranteed 0 ~ MessagePackRange.MaxFixArrayCount(15), can use this method. - /// </summary> - /// <returns></returns> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteFixedArrayHeaderUnsafe(Stream stream, int count) - { - stream.WriteByte((byte)(MessagePackCode.MinFixArray | count)); - return 1; - } - - /// <summary> - /// Write array count. - /// </summary> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteArrayHeader(Stream stream, int count) - { - checked - { - return WriteArrayHeader(stream, (uint)count); - } - } - - /// <summary> - /// Write array count. - /// </summary> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteArrayHeader(Stream stream, uint count) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteArrayHeader(ref buffer, 0, count); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - - /// <summary> - /// Write array format header, always use array32 format(length is fixed, 5). - /// </summary> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteArrayHeaderForceArray32Block(Stream stream, uint count) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteArrayHeaderForceArray32Block(ref buffer, 0, count); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteBoolean(Stream stream, bool value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteBoolean(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteByte(Stream stream, byte value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteByte(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteByteForceByteBlock(Stream stream, byte value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteByteForceByteBlock(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteBytes(Stream stream, byte[] value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteBytes(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteBytes(Stream stream, byte[] src, int srcOffset, int count) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteBytes(ref buffer, 0, src, srcOffset, count); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteSByte(Stream stream, sbyte value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteSByte(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteSByteForceSByteBlock(Stream stream, sbyte value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteSByteForceSByteBlock(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteSingle(Stream stream, float value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteSingle(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteDouble(Stream stream, double value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteDouble(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteInt16(Stream stream, short value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteInt16(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteInt16ForceInt16Block(Stream stream, short value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteInt16ForceInt16Block(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - - /// <summary> - /// Unsafe. If value is guranteed 0 ~ MessagePackCode.MaxFixInt(127), can use this method. - /// </summary> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WritePositiveFixedIntUnsafe(Stream stream, int value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WritePositiveFixedIntUnsafe(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteInt32(Stream stream, int value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteInt32(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - - /// <summary> - /// Acquire static message block(always 5 bytes). - /// </summary> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteInt32ForceInt32Block(Stream stream, int value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteInt32ForceInt32Block(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteInt64(Stream stream, long value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteInt64(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteInt64ForceInt64Block(Stream stream, long value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteInt64ForceInt64Block(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteUInt16(Stream stream, ushort value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteUInt16(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteUInt16ForceUInt16Block(Stream stream, ushort value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteUInt16ForceUInt16Block(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteUInt32(Stream stream, uint value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteUInt32(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteUInt32ForceUInt32Block(Stream stream, uint value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteUInt32ForceUInt32Block(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteUInt64(Stream stream, ulong value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteUInt64(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteUInt64ForceUInt64Block(Stream stream, ulong value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteUInt64ForceUInt64Block(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteChar(Stream stream, char value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteChar(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - - /// <summary> - /// Unsafe. If value is guranteed length is 0 ~ 31, can use this method. - /// </summary> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteFixedStringUnsafe(Stream stream, string value, int byteCount) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteFixedStringUnsafe(ref buffer, 0, value, byteCount); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - - /// <summary> - /// Unsafe. If pre-calculated byteCount of target string, can use this method. - /// </summary> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteStringUnsafe(Stream stream, string value, int byteCount) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteStringUnsafe(ref buffer, 0, value, byteCount); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteStringBytes(Stream stream, byte[] utf8stringBytes) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteStringBytes(ref buffer, 0, utf8stringBytes); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - - public static int WriteString(Stream stream, string value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteString(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - - public static int WriteStringForceStr32Block(Stream stream, string value) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteStringForceStr32Block(ref buffer, 0, value); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteExtensionFormatHeader(Stream stream, sbyte typeCode, int dataLength) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteExtensionFormatHeader(ref buffer, 0, typeCode, dataLength); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - - /// <summary> - /// Write extension format header, always use ext32 format(length is fixed, 6). - /// </summary> -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteExtensionFormatHeaderForceExt32Block(Stream stream, sbyte typeCode, int dataLength) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteExtensionFormatHeaderForceExt32Block(ref buffer, 0, typeCode, dataLength); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteExtensionFormat(Stream stream, sbyte typeCode, byte[] data) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteExtensionFormat(ref buffer, 0, typeCode, data); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - -#if !UNITY - [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] -#endif - public static int WriteDateTime(Stream stream, DateTime dateTime) - { - var buffer = StreamDecodeMemoryPool.GetBuffer(); - var writeCount = WriteDateTime(ref buffer, 0, dateTime); - stream.Write(buffer, 0, writeCount); - return writeCount; - } - } -} diff --git a/src/MessagePack/MessagePackSerializer.Json.cs b/src/MessagePack/MessagePackSerializer.Json.cs index fded4aef..47beea41 100644 --- a/src/MessagePack/MessagePackSerializer.Json.cs +++ b/src/MessagePack/MessagePackSerializer.Json.cs @@ -16,11 +16,14 @@ namespace MessagePack /// </summary> public void SerializeToJson<T>(TextWriter textWriter, T obj, IFormatterResolver resolver = null) { - var msgpackWriter = new MessagePackWriter(); - Serialize(ref msgpackWriter, obj, resolver); - msgpackWriter.Flush(); - var msgpackReader = new MessagePackReader(msgpackWriter.WrittenBytes); - ConvertToJson(ref msgpackReader, textWriter); + using (var sequence = new Sequence<byte>()) + { + var msgpackWriter = new MessagePackWriter(sequence); + Serialize(ref msgpackWriter, obj, resolver); + msgpackWriter.Flush(); + var msgpackReader = new MessagePackReader(sequence.AsReadOnlySequence); + ConvertToJson(ref msgpackReader, textWriter); + } } /// <summary> @@ -95,13 +98,16 @@ namespace MessagePack break; case TinyJsonToken.StartObject: // Set up a scratch area to serialize the collection since we don't know its length yet, which must be written first. - var scratchWriter = writer.Clone(); - var mapCount = FromJsonCore(jr, ref scratchWriter); - scratchWriter.Flush(); + using (var scratch = new Sequence<byte>()) + { + var scratchWriter = writer.Clone(scratch); + var mapCount = FromJsonCore(jr, ref scratchWriter); + scratchWriter.Flush(); - mapCount = mapCount / 2; // remove propertyname string count. - writer.WriteMapHeader(mapCount); - writer.WriteRaw(scratchWriter.WrittenBytes); + mapCount = mapCount / 2; // remove propertyname string count. + writer.WriteMapHeader(mapCount); + writer.WriteRaw(scratch.AsReadOnlySequence); + } count++; break; @@ -109,12 +115,15 @@ namespace MessagePack return count; // break case TinyJsonToken.StartArray: // Set up a scratch area to serialize the collection since we don't know its length yet, which must be written first. - scratchWriter = writer.Clone(); - var arrayCount = FromJsonCore(jr, ref scratchWriter); - scratchWriter.Flush(); + using (var scratch = new Sequence<byte>()) + { + var scratchWriter = writer.Clone(scratch); + var arrayCount = FromJsonCore(jr, ref scratchWriter); + scratchWriter.Flush(); - writer.WriteArrayHeader(arrayCount); - writer.WriteRaw(scratchWriter.WrittenBytes); + writer.WriteArrayHeader(arrayCount); + writer.WriteRaw(scratch.AsReadOnlySequence); + } count++; break; diff --git a/src/MessagePack/MessagePackSerializer.cs b/src/MessagePack/MessagePackSerializer.cs index d456f9e7..7ae2867f 100644 --- a/src/MessagePack/MessagePackSerializer.cs +++ b/src/MessagePack/MessagePackSerializer.cs @@ -64,10 +64,9 @@ namespace MessagePack resolver = this.DefaultResolver; } - var fastWriter = new MessagePackWriter(); + var fastWriter = new MessagePackWriter(writer); this.Serialize(ref fastWriter, value, resolver); fastWriter.Flush(); - writer.Write(fastWriter.WrittenBytes.ToArray()); } /// <summary> diff --git a/src/MessagePack/MessagePackWriter.cs b/src/MessagePack/MessagePackWriter.cs index 83244d77..225f8b42 100644 --- a/src/MessagePack/MessagePackWriter.cs +++ b/src/MessagePack/MessagePackWriter.cs @@ -1,15 +1,15 @@ // Copyright (c) Andrew Arnott. All rights reserved. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +using MessagePack.Formatters; +using MessagePack.Internal; +using Microsoft; using System; using System.Buffers; using System.Collections.Generic; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Text; -using MessagePack.Formatters; -using MessagePack.Internal; -using Microsoft; namespace MessagePack { @@ -21,20 +21,18 @@ namespace MessagePack /// </remarks> public ref struct MessagePackWriter { - private byte[] bytes; - - private int offset; - - private int originalOffset; + /// <summary> + /// The writer to use. + /// </summary> + private BufferWriter writer; /// <summary> /// Initializes a new instance of the <see cref="MessagePackWriter"/> struct. /// </summary> - public MessagePackWriter(byte[] bytes = null, int offset = 0) + /// <param name="writer">The writer to use.</param> + public MessagePackWriter(IBufferWriter<byte> writer) { - this.bytes = bytes; - this.originalOffset = offset; - this.offset = offset; + this.writer = new BufferWriter(writer); this.OldSpec = false; } @@ -43,14 +41,13 @@ namespace MessagePack /// </summary> public bool OldSpec { get; set; } - public ReadOnlySequence<byte> WrittenBytes => new ReadOnlySequence<byte>(this.bytes.AsMemory(this.originalOffset, this.offset - this.originalOffset)); - /// <summary> /// Initializes a new instance of the <see cref="MessagePackWriter"/> struct, /// with the same settings as this one, but with its own buffer writer. /// </summary> + /// <param name="writer">The writer to use for the new instance.</param> /// <returns>The new writer.</returns> - public MessagePackWriter Clone() => new MessagePackWriter() + public MessagePackWriter Clone(IBufferWriter<byte> writer) => new MessagePackWriter(writer) { OldSpec = this.OldSpec, }; @@ -58,39 +55,29 @@ namespace MessagePack /// <summary> /// Ensures everything previously written has been flushed to the underlying <see cref="IBufferWriter{T}"/>. /// </summary> - public void Flush() { } + public void Flush() => this.writer.Commit(); /// <summary> /// Writes a <see cref="MessagePackCode.Nil"/> value. /// </summary> - public void WriteNil() => this.offset += MessagePackBinary.WriteNil(ref this.bytes, this.offset); + public void WriteNil() + { + var span = writer.GetSpan(1); + span[0] = MessagePackCode.Nil; + writer.Advance(1); + } /// <summary> /// Copies bytes directly into the message pack writer. /// </summary> /// <param name="rawMessagePackBlock">The span of bytes to copy from.</param> - public void WriteRaw(ReadOnlySpan<byte> rawMessagePackBlock) - { - var span = this.GetSpan(rawMessagePackBlock.Length); - rawMessagePackBlock.CopyTo(span); - this.Advance(rawMessagePackBlock.Length); - } + public void WriteRaw(ReadOnlySpan<byte> rawMessagePackBlock) => writer.Write(rawMessagePackBlock); /// <summary> /// Copies bytes directly into the message pack writer. /// </summary> /// <param name="rawMessagePackBlock">The span of bytes to copy from.</param> - public void WriteRaw(ReadOnlySequence<byte> rawMessagePackBlock) - { - var span = this.GetSpan((int)rawMessagePackBlock.Length); - foreach (var segment in rawMessagePackBlock) - { - segment.Span.CopyTo(span); - span = span.Slice(segment.Length); - } - - this.Advance((int)rawMessagePackBlock.Length); - } + public void WriteRaw(ReadOnlySequence<byte> rawMessagePackBlock) => rawMessagePackBlock.CopyTo(ref writer); /// <summary> /// Write the length of the next array to be written in the most compact form of @@ -99,7 +86,7 @@ namespace MessagePack /// <see cref="MessagePackCode.Array32"/> /// </summary> /// <param name="count">The number of elements that will be written in the array.</param> - public void WriteArrayHeader(int count) => this.offset += MessagePackBinary.WriteArrayHeader(ref this.bytes, this.offset, count); + public void WriteArrayHeader(int count) => WriteArrayHeader((uint)count); /// <summary> /// Write the length of the next array to be written in the most compact form of @@ -109,7 +96,27 @@ namespace MessagePack /// </summary> /// <param name="count">The number of elements that will be written in the array.</param> [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteArrayHeader(uint count) => this.offset += MessagePackBinary.WriteArrayHeader(ref this.bytes, this.offset, count); + public void WriteArrayHeader(uint count) + { + if (count <= MessagePackRange.MaxFixArrayCount) + { + WriteFixedArrayHeaderUnsafe(count); + } + else if (count <= ushort.MaxValue) + { + var span = writer.GetSpan(3); + span[0] = MessagePackCode.Array16; + WriteBigEndian((ushort)count, span.Slice(1)); + writer.Advance(3); + } + else + { + var span = writer.GetSpan(5); + span[0] = MessagePackCode.Array32; + WriteBigEndian(count, span.Slice(1)); + writer.Advance(5); + } + } /// <summary> /// Write the length of the next array to be written as <see cref="MessagePackCode.MinFixArray"/>. @@ -120,7 +127,12 @@ namespace MessagePack /// </param> [EditorBrowsable(EditorBrowsableState.Never)] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteFixedArrayHeaderUnsafe(uint count) => this.offset += MessagePackBinary.WriteFixedArrayHeaderUnsafe(ref this.bytes, this.offset, (int)count); + public void WriteFixedArrayHeaderUnsafe(uint count) + { + var span = writer.GetSpan(1); + span[0] = (byte)(MessagePackCode.MinFixArray | count); + writer.Advance(1); + } /// <summary> /// Write the length of the next map to be written in the most compact form of @@ -129,7 +141,7 @@ namespace MessagePack /// <see cref="MessagePackCode.Map32"/> /// </summary> /// <param name="count">The number of key=value pairs that will be written in the map.</param> - public void WriteMapHeader(int count) => this.offset += MessagePackBinary.WriteMapHeader(ref this.bytes, this.offset, count); + public void WriteMapHeader(int count) => WriteMapHeader((uint)count); /// <summary> /// Write the length of the next map to be written in the most compact form of @@ -138,43 +150,126 @@ namespace MessagePack /// <see cref="MessagePackCode.Map32"/> /// </summary> /// <param name="count">The number of key=value pairs that will be written in the map.</param> - public void WriteMapHeader(uint count) => this.offset += MessagePackBinary.WriteMapHeader(ref this.bytes, this.offset, count); + public void WriteMapHeader(uint count) + { + if (count <= MessagePackRange.MaxFixMapCount) + { + var span = writer.GetSpan(1); + span[0] = (byte)(MessagePackCode.MinFixMap | count); + writer.Advance(1); + } + else if (count <= ushort.MaxValue) + { + var span = writer.GetSpan(3); + span[0] = MessagePackCode.Map16; + WriteBigEndian((ushort)count, span.Slice(1)); + writer.Advance(3); + } + else + { + var span = writer.GetSpan(5); + span[0] = MessagePackCode.Map32; + WriteBigEndian(count, span.Slice(1)); + writer.Advance(5); + } + } /// <summary> /// Writes a <see cref="byte"/> value using a 1-byte code when possible, otherwise as <see cref="MessagePackCode.UInt8"/>. /// </summary> /// <param name="value">The value.</param> - public void Write(byte value) => this.offset += MessagePackBinary.WriteByte(ref this.bytes, this.offset, value); + public void Write(byte value) + { + if (value <= MessagePackCode.MaxFixInt) + { + var span = writer.GetSpan(1); + span[0] = value; + writer.Advance(1); + } + else + { + WriteUInt8(value); + } + } /// <summary> /// Writes a <see cref="byte"/> value using <see cref="MessagePackCode.UInt8"/>. /// </summary> /// <param name="value">The value.</param> - public void WriteUInt8(byte value) => this.offset += MessagePackBinary.WriteByteForceByteBlock(ref this.bytes, this.offset, value); + public void WriteUInt8(byte value) + { + var span = writer.GetSpan(2); + span[0] = MessagePackCode.UInt8; + span[1] = value; + writer.Advance(2); + } /// <summary> /// Writes an 8-bit value using a 1-byte code when possible, otherwise as <see cref="MessagePackCode.Int8"/>. /// </summary> /// <param name="value">The value.</param> - public void Write(sbyte value) => this.offset += MessagePackBinary.WriteSByte(ref this.bytes, this.offset, value); + public void Write(sbyte value) + { + if (value < MessagePackRange.MinFixNegativeInt) + { + WriteInt8(value); + } + else + { + var span = writer.GetSpan(1); + span[0] = unchecked((byte)value); + writer.Advance(1); + } + } /// <summary> /// Writes an 8-bit value using <see cref="MessagePackCode.Int8"/>. /// </summary> /// <param name="value">The value.</param> - public void WriteInt8(sbyte value) => this.offset += MessagePackBinary.WriteSByteForceSByteBlock(ref this.bytes, this.offset, value); + public void WriteInt8(sbyte value) + { + var span = writer.GetSpan(2); + span[0] = MessagePackCode.Int8; + span[1] = unchecked((byte)value); + writer.Advance(2); + } /// <summary> /// Writes a <see cref="ushort"/> value using a 1-byte code when possible, otherwise as <see cref="MessagePackCode.UInt8"/> or <see cref="MessagePackCode.UInt16"/>. /// </summary> /// <param name="value">The value.</param> - public void Write(ushort value) => this.offset += MessagePackBinary.WriteUInt16(ref this.bytes, this.offset, value); + public void Write(ushort value) + { + if (value <= MessagePackRange.MaxFixPositiveInt) + { + var span = writer.GetSpan(1); + span[0] = unchecked((byte)value); + writer.Advance(1); + } + else if (value <= byte.MaxValue) + { + var span = writer.GetSpan(2); + span[0] = MessagePackCode.UInt8; + span[1] = unchecked((byte)value); + writer.Advance(2); + } + else + { + WriteUInt16(value); + } + } /// <summary> /// Writes a <see cref="ushort"/> value using <see cref="MessagePackCode.UInt16"/>. /// </summary> /// <param name="value">The value.</param> - public void WriteUInt16(ushort value) => this.offset += MessagePackBinary.WriteUInt16ForceUInt16Block(ref this.bytes, this.offset, value); + public void WriteUInt16(ushort value) + { + var span = writer.GetSpan(3); + span[0] = MessagePackCode.UInt16; + WriteBigEndian(value, span.Slice(1)); + writer.Advance(3); + } /// <summary> /// Writes a <see cref="short"/> using a built-in 1-byte code when within specific MessagePack-supported ranges, @@ -185,13 +280,46 @@ namespace MessagePack /// <see cref="MessagePackCode.Int16"/> /// </summary> /// <param name="value">The value to write.</param> - public void Write(short value) => this.offset += MessagePackBinary.WriteInt16(ref this.bytes, this.offset, value); + public void Write(short value) + { + if (value >= 0) + { + Write((ushort)value); + } + else + { + // negative int(use int) + if (MessagePackRange.MinFixNegativeInt <= value) + { + var span = writer.GetSpan(1); + span[0] = unchecked((byte)value); + writer.Advance(1); + } + else if (sbyte.MinValue <= value) + { + var span = writer.GetSpan(2); + span[0] = MessagePackCode.Int8; + span[1] = unchecked((byte)value); + writer.Advance(2); + } + else + { + WriteInt16(value); + } + } + } /// <summary> /// Writes a <see cref="short"/> using <see cref="MessagePackCode.Int16"/>. /// </summary> /// <param name="value">The value to write.</param> - public void WriteInt16(short value) => this.offset += MessagePackBinary.WriteInt16ForceInt16Block(ref this.bytes, this.offset, value); + public void WriteInt16(short value) + { + var span = writer.GetSpan(3); + span[0] = MessagePackCode.Int16; + WriteBigEndian(value, span.Slice(1)); + writer.Advance(3); + } /// <summary> /// Writes an <see cref="uint"/> using a built-in 1-byte code when within specific MessagePack-supported ranges, @@ -202,13 +330,45 @@ namespace MessagePack /// </summary> /// <param name="value">The value to write.</param> [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Write(uint value) => this.offset += MessagePackBinary.WriteUInt32(ref this.bytes, this.offset, value); + public void Write(uint value) + { + if (value <= MessagePackRange.MaxFixPositiveInt) + { + var span = writer.GetSpan(1); + span[0] = unchecked((byte)value); + writer.Advance(1); + } + else if (value <= byte.MaxValue) + { + var span = writer.GetSpan(2); + span[0] = MessagePackCode.UInt8; + span[1] = unchecked((byte)value); + writer.Advance(2); + } + else if (value <= ushort.MaxValue) + { + var span = writer.GetSpan(3); + span[0] = MessagePackCode.UInt16; + WriteBigEndian((ushort)value, span.Slice(1)); + writer.Advance(3); + } + else + { + WriteUInt32(value); + } + } /// <summary> /// Writes an <see cref="uint"/> using <see cref="MessagePackCode.UInt32"/>. /// </summary> /// <param name="value">The value to write.</param> - public void WriteUInt32(uint value) => this.offset += MessagePackBinary.WriteUInt32ForceUInt32Block(ref this.bytes, this.offset, value); + public void WriteUInt32(uint value) + { + var span = writer.GetSpan(5); + span[0] = MessagePackCode.UInt32; + WriteBigEndian(value, span.Slice(1)); + writer.Advance(5); + } /// <summary> /// Writes an <see cref="int"/> using a built-in 1-byte code when within specific MessagePack-supported ranges, @@ -222,13 +382,53 @@ namespace MessagePack /// </summary> /// <param name="value">The value to write.</param> [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Write(int value) => this.offset += MessagePackBinary.WriteInt32(ref this.bytes, this.offset, value); + public void Write(int value) + { + if (value >= 0) + { + Write((uint)value); + } + else + { + // negative int(use int) + if (MessagePackRange.MinFixNegativeInt <= value) + { + var span = writer.GetSpan(1); + span[0] = unchecked((byte)value); + writer.Advance(1); + } + else if (sbyte.MinValue <= value) + { + var span = writer.GetSpan(2); + span[0] = MessagePackCode.Int8; + span[1] = unchecked((byte)value); + writer.Advance(2); + } + else if (short.MinValue <= value) + { + var span = writer.GetSpan(3); + span[0] = MessagePackCode.Int16; + WriteBigEndian((short)value, span.Slice(1)); + writer.Advance(3); + } + else + { + WriteInt32(value); + } + } + } /// <summary> /// Writes an <see cref="int"/> using <see cref="MessagePackCode.Int32"/>. /// </summary> /// <param name="value">The value to write.</param> - public void WriteInt32(int value) => this.offset += MessagePackBinary.WriteInt32ForceInt32Block(ref this.bytes, this.offset, value); + public void WriteInt32(int value) + { + var span = writer.GetSpan(5); + span[0] = MessagePackCode.Int32; + WriteBigEndian(value, span.Slice(1)); + writer.Advance(5); + } /// <summary> /// Writes an <see cref="ulong"/> using a built-in 1-byte code when within specific MessagePack-supported ranges, @@ -236,16 +436,57 @@ namespace MessagePack /// <see cref="MessagePackCode.UInt8"/>, /// <see cref="MessagePackCode.UInt16"/>, /// <see cref="MessagePackCode.UInt32"/>, - /// <see cref="MessagePackCode.UInt64"/>. + /// <see cref="MessagePackCode.Int8"/>, + /// <see cref="MessagePackCode.Int16"/>, + /// <see cref="MessagePackCode.Int32"/> /// </summary> /// <param name="value">The value to write.</param> - public void Write(ulong value) => this.offset += MessagePackBinary.WriteUInt64(ref this.bytes, this.offset, value); + public void Write(ulong value) + { + if (value <= MessagePackRange.MaxFixPositiveInt) + { + var span = writer.GetSpan(1); + span[0] = unchecked((byte)value); + writer.Advance(1); + } + else if (value <= byte.MaxValue) + { + var span = writer.GetSpan(2); + span[0] = MessagePackCode.UInt8; + span[1] = unchecked((byte)value); + writer.Advance(2); + } + else if (value <= ushort.MaxValue) + { + var span = writer.GetSpan(3); + span[0] = MessagePackCode.UInt16; + WriteBigEndian((ushort)value, span.Slice(1)); + writer.Advance(3); + } + else if (value <= uint.MaxValue) + { + var span = writer.GetSpan(5); + span[0] = MessagePackCode.UInt32; + WriteBigEndian((uint)value, span.Slice(1)); + writer.Advance(5); + } + else + { + WriteUInt64(value); + } + } /// <summary> - /// Writes an <see cref="ulong"/> using <see cref="MessagePackCode.UInt64"/>. + /// Writes an <see cref="ulong"/> using <see cref="MessagePackCode.Int32"/>. /// </summary> /// <param name="value">The value to write.</param> - public void WriteUInt64(ulong value) => this.offset += MessagePackBinary.WriteUInt64ForceUInt64Block(ref this.bytes, this.offset, value); + public void WriteUInt64(ulong value) + { + var span = writer.GetSpan(9); + span[0] = MessagePackCode.UInt64; + WriteBigEndian(value, span.Slice(1)); + writer.Advance(9); + } /// <summary> /// Writes an <see cref="long"/> using a built-in 1-byte code when within specific MessagePack-supported ranges, @@ -260,7 +501,48 @@ namespace MessagePack /// <see cref="MessagePackCode.Int64"/> /// </summary> /// <param name="value">The value to write.</param> - public void Write(long value) => this.offset += MessagePackBinary.WriteInt64(ref this.bytes, this.offset, value); + public void Write(long value) + { + if (value >= 0) + { + Write((ulong)value); + } + else + { + // negative int(use int) + if (MessagePackRange.MinFixNegativeInt <= value) + { + var span = writer.GetSpan(1); + span[0] = unchecked((byte)value); + writer.Advance(1); + } + else if (sbyte.MinValue <= value) + { + var span = writer.GetSpan(2); + span[0] = MessagePackCode.Int8; + span[1] = unchecked((byte)value); + writer.Advance(2); + } + else if (short.MinValue <= value) + { + var span = writer.GetSpan(3); + span[0] = MessagePackCode.Int16; + WriteBigEndian((short)value, span.Slice(1)); + writer.Advance(3); + } + else if (int.MinValue <= value) + { + var span = writer.GetSpan(5); + span[0] = MessagePackCode.Int32; + WriteBigEndian((int)value, span.Slice(1)); + writer.Advance(5); + } + else + { + WriteInt64(value); + } + } + } /// <summary> /// Writes an <see cref="long"/> using a built-in 1-byte code when within specific MessagePack-supported ranges, @@ -275,31 +557,96 @@ namespace MessagePack /// <see cref="MessagePackCode.Int64"/> /// </summary> /// <param name="value">The value to write.</param> - public void WriteInt64(long value) => this.offset += MessagePackBinary.WriteInt64ForceInt64Block(ref this.bytes, this.offset, value); + public void WriteInt64(long value) + { + var span = writer.GetSpan(9); + span[0] = MessagePackCode.Int64; + WriteBigEndian(value, span.Slice(1)); + writer.Advance(9); + } /// <summary> /// Writes a <see cref="bool"/> value using either <see cref="MessagePackCode.True"/> or <see cref="MessagePackCode.False"/>. /// </summary> /// <param name="value">The value.</param> - public void Write(bool value) => this.offset += MessagePackBinary.WriteBoolean(ref this.bytes, this.offset, value); + public void Write(bool value) + { + var span = writer.GetSpan(1); + span[0] = value ? MessagePackCode.True : MessagePackCode.False; + writer.Advance(1); + } /// <summary> /// Writes a <see cref="char"/> value using a 1-byte code when possible, otherwise as <see cref="MessagePackCode.UInt8"/> or <see cref="MessagePackCode.UInt16"/>. /// </summary> /// <param name="value">The value.</param> - public void Write(char value) => this.offset += MessagePackBinary.WriteChar(ref this.bytes, this.offset, value); + public void Write(char value) => this.Write((ushort)value); /// <summary> /// Writes a <see cref="MessagePackCode.Float32"/> value. /// </summary> /// <param name="value">The value.</param> - public void Write(float value) => this.offset += MessagePackBinary.WriteSingle(ref this.bytes, this.offset, value); + public void Write(float value) + { + var span = writer.GetSpan(5); + + span[0] = MessagePackCode.Float32; + + var num = new Float32Bits(value); + if (BitConverter.IsLittleEndian) + { + span[1] = num.Byte3; + span[2] = num.Byte2; + span[3] = num.Byte1; + span[4] = num.Byte0; + } + else + { + span[1] = num.Byte0; + span[2] = num.Byte1; + span[3] = num.Byte2; + span[4] = num.Byte3; + } + + writer.Advance(5); + } /// <summary> /// Writes a <see cref="MessagePackCode.Float64"/> value. /// </summary> /// <param name="value">The value.</param> - public void Write(double value) => this.offset += MessagePackBinary.WriteDouble(ref this.bytes, this.offset, value); + public void Write(double value) + { + var span = writer.GetSpan(9); + + span[0] = MessagePackCode.Float64; + + var num = new Float64Bits(value); + if (BitConverter.IsLittleEndian) + { + span[1] = num.Byte7; + span[2] = num.Byte6; + span[3] = num.Byte5; + span[4] = num.Byte4; + span[5] = num.Byte3; + span[6] = num.Byte2; + span[7] = num.Byte1; + span[8] = num.Byte0; + } + else + { + span[1] = num.Byte0; + span[2] = num.Byte1; + span[3] = num.Byte2; + span[4] = num.Byte3; + span[5] = num.Byte4; + span[6] = num.Byte5; + span[7] = num.Byte6; + span[8] = num.Byte7; + } + + writer.Advance(9); + } /// <summary> /// Writes a <see cref="DateTime"/> using the message code <see cref="ReservedMessagePackExtensionTypeCode.DateTime"/>. @@ -313,7 +660,79 @@ namespace MessagePack } else { - this.offset += MessagePackBinary.WriteDateTime(ref this.bytes, this.offset, dateTime); + // Timestamp spec + // https://github.com/msgpack/msgpack/pull/209 + // FixExt4(-1) => seconds | [1970-01-01 00:00:00 UTC, 2106-02-07 06:28:16 UTC) range + // FixExt8(-1) => nanoseconds + seconds | [1970-01-01 00:00:00.000000000 UTC, 2514-05-30 01:53:04.000000000 UTC) range + // Ext8(12,-1) => nanoseconds + seconds | [-584554047284-02-23 16:59:44 UTC, 584554051223-11-09 07:00:16.000000000 UTC) range + dateTime = dateTime.ToUniversalTime(); + + var secondsSinceBclEpoch = dateTime.Ticks / TimeSpan.TicksPerSecond; + var seconds = secondsSinceBclEpoch - DateTimeConstants.BclSecondsAtUnixEpoch; + var nanoseconds = (dateTime.Ticks % TimeSpan.TicksPerSecond) * DateTimeConstants.NanosecondsPerTick; + + // reference pseudo code. + /* + struct timespec { + long tv_sec; // seconds + long tv_nsec; // nanoseconds + } time; + if ((time.tv_sec >> 34) == 0) + { + uint64_t data64 = (time.tv_nsec << 34) | time.tv_sec; + if (data & 0xffffffff00000000L == 0) + { + // timestamp 32 + uint32_t data32 = data64; + serialize(0xd6, -1, data32) + } + else + { + // timestamp 64 + serialize(0xd7, -1, data64) + } + } + else + { + // timestamp 96 + serialize(0xc7, 12, -1, time.tv_nsec, time.tv_sec) + } + */ + + if ((seconds >> 34) == 0) + { + var data64 = unchecked((ulong)((nanoseconds << 34) | seconds)); + if ((data64 & 0xffffffff00000000L) == 0) + { + // timestamp 32(seconds in 32-bit unsigned int) + var data32 = (UInt32)data64; + var span = writer.GetSpan(6); + span[0] = MessagePackCode.FixExt4; + span[1] = unchecked((byte)ReservedMessagePackExtensionTypeCode.DateTime); + WriteBigEndian(data32, span.Slice(2)); + writer.Advance(6); + } + else + { + // timestamp 64(nanoseconds in 30-bit unsigned int | seconds in 34-bit unsigned int) + var span = writer.GetSpan(10); + span[0] = MessagePackCode.FixExt8; + span[1] = unchecked((byte)ReservedMessagePackExtensionTypeCode.DateTime); + WriteBigEndian(data64, span.Slice(2)); + writer.Advance(10); + } + } + else + { + // timestamp 96( nanoseconds in 32-bit unsigned int | seconds in 64-bit signed int ) + var span = writer.GetSpan(15); + span[0] = MessagePackCode.Ext8; + span[1] = 12; + span[2] = unchecked((byte)ReservedMessagePackExtensionTypeCode.DateTime); + WriteBigEndian((uint)nanoseconds, span.Slice(3)); + WriteBigEndian(seconds, span.Slice(7)); + writer.Advance(15); + } } } @@ -324,7 +743,48 @@ namespace MessagePack /// <see cref="MessagePackCode.Bin32"/>, /// </summary> /// <param name="src">The span of bytes to write.</param> - public void Write(ReadOnlySpan<byte> src) => this.offset += this.OldSpec ? MessagePackBinary.WriteStringBytes(ref this.bytes, offset, src.ToArray()) : MessagePackBinary.WriteBytes(ref this.bytes, this.offset, src.ToArray()); + public void Write(ReadOnlySpan<byte> src) + { + if (this.OldSpec) + { + WriteString(src); + return; + } + + if (src.Length <= byte.MaxValue) + { + var size = src.Length + 2; + var span = writer.GetSpan(size); + + span[0] = MessagePackCode.Bin8; + span[1] = (byte)src.Length; + + src.CopyTo(span.Slice(2)); + writer.Advance(size); + } + else if (src.Length <= UInt16.MaxValue) + { + var size = src.Length + 3; + var span = writer.GetSpan(size); + + span[0] = MessagePackCode.Bin16; + WriteBigEndian((ushort)src.Length, span.Slice(1)); + + src.CopyTo(span.Slice(3)); + writer.Advance(size); + } + else + { + var size = src.Length + 5; + var span = writer.GetSpan(size); + + span[0] = MessagePackCode.Bin32; + WriteBigEndian(src.Length, span.Slice(1)); + + src.CopyTo(span.Slice(5)); + writer.Advance(size); + } + } /// <summary> /// Writes a sequence of bytes, prefixed with a length encoded as the smallest fitting from: @@ -333,7 +793,48 @@ namespace MessagePack /// <see cref="MessagePackCode.Bin32"/>, /// </summary> /// <param name="src">The span of bytes to write.</param> - public void Write(ReadOnlySequence<byte> src) => this.offset += this.OldSpec ? MessagePackBinary.WriteStringBytes(ref this.bytes, offset, src.ToArray()) : MessagePackBinary.WriteBytes(ref this.bytes, this.offset, src.ToArray()); + public void Write(ReadOnlySequence<byte> src) + { + if (this.OldSpec) + { + WriteString(src); + return; + } + + if (src.Length <= byte.MaxValue) + { + var size = (int)src.Length + 2; + var span = writer.GetSpan(size); + + span[0] = MessagePackCode.Bin8; + span[1] = (byte)src.Length; + + src.CopyTo(span.Slice(2)); + writer.Advance(size); + } + else if (src.Length <= UInt16.MaxValue) + { + var size = (int)src.Length + 3; + var span = writer.GetSpan(size); + + span[0] = MessagePackCode.Bin16; + WriteBigEndian((ushort)src.Length, span.Slice(1)); + + src.CopyTo(span.Slice(3)); + writer.Advance(size); + } + else + { + var size = (int)src.Length + 5; + var span = writer.GetSpan(size); + + span[0] = MessagePackCode.Bin32; + WriteBigEndian(src.Length, span.Slice(1)); + + src.CopyTo(span.Slice(5)); + writer.Advance(size); + } + } /// <summary> /// Writes out an array of bytes that (may) represent a UTF-8 encoded string, prefixed with the length using one of these message codes: @@ -343,7 +844,41 @@ namespace MessagePack /// <see cref="MessagePackCode.Str32"/>, /// </summary> /// <param name="utf8stringBytes">The bytes to write.</param> - public void WriteString(ReadOnlySequence<byte> utf8stringBytes) => this.offset += MessagePackBinary.WriteStringBytes(ref this.bytes, this.offset, utf8stringBytes.ToArray()); + public void WriteString(ReadOnlySequence<byte> utf8stringBytes) + { + var byteCount = (int)utf8stringBytes.Length; + if (byteCount <= MessagePackRange.MaxFixStringLength) + { + var span = writer.GetSpan(byteCount + 1); + span[0] = (byte)(MessagePackCode.MinFixStr | byteCount); + utf8stringBytes.CopyTo(span.Slice(1)); + writer.Advance(byteCount + 1); + } + else if (byteCount <= byte.MaxValue && !this.OldSpec) + { + var span = writer.GetSpan(byteCount + 2); + span[0] = MessagePackCode.Str8; + span[1] = unchecked((byte)byteCount); + utf8stringBytes.CopyTo(span.Slice(2)); + writer.Advance(byteCount + 2); + } + else if (byteCount <= ushort.MaxValue) + { + var span = writer.GetSpan(byteCount + 3); + span[0] = MessagePackCode.Str16; + WriteBigEndian((ushort)byteCount, span.Slice(1)); + utf8stringBytes.CopyTo(span.Slice(3)); + writer.Advance(byteCount + 3); + } + else + { + var span = writer.GetSpan(byteCount + 5); + span[0] = MessagePackCode.Str32; + WriteBigEndian(byteCount, span.Slice(1)); + utf8stringBytes.CopyTo(span.Slice(5)); + writer.Advance(byteCount + 5); + } + } /// <summary> /// Writes out an array of bytes that (may) represent a UTF-8 encoded string, prefixed with the length using one of these message codes: @@ -353,7 +888,41 @@ namespace MessagePack /// <see cref="MessagePackCode.Str32"/>, /// </summary> /// <param name="utf8stringBytes">The bytes to write.</param> - public void WriteString(ReadOnlySpan<byte> utf8stringBytes) => this.offset += MessagePackBinary.WriteStringBytes(ref this.bytes, this.offset, utf8stringBytes.ToArray()); + public void WriteString(ReadOnlySpan<byte> utf8stringBytes) + { + var byteCount = utf8stringBytes.Length; + if (byteCount <= MessagePackRange.MaxFixStringLength) + { + var span = writer.GetSpan(byteCount + 1); + span[0] = (byte)(MessagePackCode.MinFixStr | byteCount); + utf8stringBytes.CopyTo(span.Slice(1)); + writer.Advance(byteCount + 1); + } + else if (byteCount <= byte.MaxValue && !this.OldSpec) + { + var span = writer.GetSpan(byteCount + 2); + span[0] = MessagePackCode.Str8; + span[1] = unchecked((byte)byteCount); + utf8stringBytes.CopyTo(span.Slice(2)); + writer.Advance(byteCount + 2); + } + else if (byteCount <= ushort.MaxValue) + { + var span = writer.GetSpan(byteCount + 3); + span[0] = MessagePackCode.Str16; + WriteBigEndian((ushort)byteCount, span.Slice(1)); + utf8stringBytes.CopyTo(span.Slice(3)); + writer.Advance(byteCount + 3); + } + else + { + var span = writer.GetSpan(byteCount + 5); + span[0] = MessagePackCode.Str32; + WriteBigEndian(byteCount, span.Slice(1)); + utf8stringBytes.CopyTo(span.Slice(5)); + writer.Advance(byteCount + 5); + } + } /// <summary> /// Writes out a <see cref="string"/>, prefixed with the length using one of these message codes: @@ -364,7 +933,21 @@ namespace MessagePack /// </summary> /// <param name="value">The value to write. Must not be null.</param> [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Write(string value) => this.offset += MessagePackBinary.WriteString(ref this.bytes, this.offset, value, this.OldSpec); + public unsafe void Write(string value) + { + if (value == null) + { + ThrowArgumentNullException(nameof(value)); + } + + ref byte buffer = ref WriteString_PrepareSpan(value.Length, out int bufferSize, out int useOffset); + fixed (char* pValue = value) + fixed (byte* pBuffer = &buffer) + { + int byteCount = StringEncoding.UTF8.GetBytes(pValue, value.Length, pBuffer + useOffset, bufferSize); + WriteString_PostEncoding(pBuffer, useOffset, byteCount); + } + } /// <summary> /// Writes out a <see cref="string"/>, prefixed with the length using one of these message codes: @@ -374,7 +957,16 @@ namespace MessagePack /// <see cref="MessagePackCode.Str32"/>, /// </summary> /// <param name="value">The value to write.</param> - public void Write(ReadOnlySpan<char> value) => this.offset += MessagePackBinary.WriteString(ref this.bytes, this.offset, value, this.OldSpec); + public unsafe void Write(ReadOnlySpan<char> value) + { + ref byte buffer = ref WriteString_PrepareSpan(value.Length, out int bufferSize, out int useOffset); + fixed (char* pValue = value) + fixed (byte* pBuffer = &buffer) + { + int byteCount = StringEncoding.UTF8.GetBytes(pValue, value.Length, pBuffer + useOffset, bufferSize); + WriteString_PostEncoding(pBuffer, useOffset, byteCount); + } + } /// <summary> /// Writes the extension format header, using the smallest one of these codes: @@ -388,7 +980,74 @@ namespace MessagePack /// <see cref="MessagePackCode.Ext32"/>. /// </summary> /// <param name="extensionHeader">The extension header.</param> - public void WriteExtensionFormatHeader(ExtensionHeader extensionHeader) => this.offset += MessagePackBinary.WriteExtensionFormatHeader(ref this.bytes, this.offset, extensionHeader.TypeCode, (int)extensionHeader.Length); + public void WriteExtensionFormatHeader(ExtensionHeader extensionHeader) + { + int dataLength = (int)extensionHeader.Length; + byte typeCode = (byte)extensionHeader.TypeCode; + switch (dataLength) + { + case 1: + var span = writer.GetSpan(2); + span[0] = MessagePackCode.FixExt1; + span[1] = unchecked(typeCode); + writer.Advance(2); + return; + case 2: + span = writer.GetSpan(2); + span[0] = MessagePackCode.FixExt2; + span[1] = unchecked(typeCode); + writer.Advance(2); + return; + case 4: + span = writer.GetSpan(2); + span[0] = MessagePackCode.FixExt4; + span[1] = unchecked(typeCode); + writer.Advance(2); + return; + case 8: + span = writer.GetSpan(2); + span[0] = MessagePackCode.FixExt8; + span[1] = unchecked(typeCode); + writer.Advance(2); + return; + case 16: + span = writer.GetSpan(2); + span[0] = MessagePackCode.FixExt16; + span[1] = unchecked(typeCode); + writer.Advance(2); + return; + default: + unchecked + { + if (dataLength <= byte.MaxValue) + { + span = writer.GetSpan(dataLength + 3); + span[0] = MessagePackCode.Ext8; + span[1] = unchecked((byte)dataLength); + span[2] = unchecked(typeCode); + writer.Advance(3); + } + else if (dataLength <= UInt16.MaxValue) + { + span = writer.GetSpan(dataLength + 4); + span[0] = MessagePackCode.Ext16; + WriteBigEndian((ushort)dataLength, span.Slice(1)); + span[3] = unchecked(typeCode); + writer.Advance(4); + } + else + { + span = writer.GetSpan(dataLength + 6); + span[0] = MessagePackCode.Ext32; + WriteBigEndian(dataLength, span.Slice(1)); + span[5] = unchecked(typeCode); + writer.Advance(6); + } + } + + break; + } + } /// <summary> /// Writes an extension format, using the smallest one of these codes: @@ -402,14 +1061,210 @@ namespace MessagePack /// <see cref="MessagePackCode.Ext32"/>. /// </summary> /// <param name="extensionData">The extension data.</param> - public void WriteExtensionFormat(ExtensionResult extensionData) => this.offset += MessagePackBinary.WriteExtensionFormat(ref this.bytes, this.offset, extensionData.TypeCode, extensionData.Data.ToArray()); + public void WriteExtensionFormat(ExtensionResult extensionData) + { + WriteExtensionFormatHeader(extensionData.Header); + WriteRaw(extensionData.Data); + } + + /// <summary> + /// Writes a 16-bit integer in big endian format. + /// </summary> + /// <param name="value">The integer.</param> + internal void WriteBigEndian(ushort value) + { + var span = writer.GetSpan(2); + WriteBigEndian(value, span); + writer.Advance(2); + } + + /// <summary> + /// Writes a 32-bit integer in big endian format. + /// </summary> + /// <param name="value">The integer.</param> + internal void WriteBigEndian(uint value) + { + var span = writer.GetSpan(4); + WriteBigEndian(value, span); + writer.Advance(4); + } + + /// <summary> + /// Writes a 64-bit integer in big endian format. + /// </summary> + /// <param name="value">The integer.</param> + internal void WriteBigEndian(ulong value) + { + var span = writer.GetSpan(8); + WriteBigEndian(value, span); + writer.Advance(8); + } + + internal Span<byte> GetSpan(int length) => writer.GetSpan(length); + + internal void Advance(int length) => writer.Advance(length); - internal Span<byte> GetSpan(int length) + private static void WriteBigEndian(short value, Span<byte> span) => WriteBigEndian(unchecked((ushort)value), span); + + private static void WriteBigEndian(int value, Span<byte> span) => WriteBigEndian(unchecked((uint)value), span); + + private static void WriteBigEndian(long value, Span<byte> span) => WriteBigEndian(unchecked((ulong)value), span); + + private static void WriteBigEndian(ushort value, Span<byte> span) { - MessagePackBinary.EnsureCapacity(ref this.bytes, this.offset, length); - return this.bytes.AsSpan(this.offset); + unchecked + { + // Write to highest index first so the JIT skips bounds checks on subsequent writes. + span[1] = (byte)value; + span[0] = (byte)(value >> 8); + } } - internal void Advance(int length) => this.offset += length; + private static unsafe void WriteBigEndian(ushort value, byte* span) + { + unchecked + { + span[0] = (byte)(value >> 8); + span[1] = (byte)value; + } + } + + private static void WriteBigEndian(uint value, Span<byte> span) + { + unchecked + { + // Write to highest index first so the JIT skips bounds checks on subsequent writes. + span[3] = (byte)value; + span[2] = (byte)(value >> 8); + span[1] = (byte)(value >> 16); + span[0] = (byte)(value >> 24); + } + } + + private static unsafe void WriteBigEndian(uint value, byte* span) + { + unchecked + { + span[0] = (byte)(value >> 24); + span[1] = (byte)(value >> 16); + span[2] = (byte)(value >> 8); + span[3] = (byte)value; + } + } + + private static void WriteBigEndian(ulong value, Span<byte> span) + { + unchecked + { + // Write to highest index first so the JIT skips bounds checks on subsequent writes. + span[7] = (byte)value; + span[6] = (byte)(value >> 8); + span[5] = (byte)(value >> 16); + span[4] = (byte)(value >> 24); + span[3] = (byte)(value >> 32); + span[2] = (byte)(value >> 40); + span[1] = (byte)(value >> 48); + span[0] = (byte)(value >> 56); + } + } + + private static void ThrowArgumentNullException(string parameterName) => throw new ArgumentNullException(parameterName); + + /// <summary> + /// Estimates the length of the header required for a given string. + /// </summary> + /// <param name="characterLength">The length of the string to be written, in characters.</param> + /// <param name="bufferSize">Receives the guaranteed length of the returned buffer.</param> + /// <param name="encodedBytesOffset">Receives the offset within the returned buffer to write the encoded string to.</param> + /// <returns> + /// A reference to the first byte in the buffer. + /// </returns> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private ref byte WriteString_PrepareSpan(int characterLength, out int bufferSize, out int encodedBytesOffset) + { + // MaxByteCount -> WritePrefix -> GetBytes has some overheads of `MaxByteCount` + // solves heuristic length check + + // ensure buffer by MaxByteCount(faster than GetByteCount) + bufferSize = StringEncoding.UTF8.GetMaxByteCount(characterLength) + 5; + ref byte buffer = ref this.writer.GetPointer(bufferSize); + + int useOffset; + if (characterLength <= MessagePackRange.MaxFixStringLength) + { + useOffset = 1; + } + else if (characterLength <= byte.MaxValue && !this.OldSpec) + { + useOffset = 2; + } + else if (characterLength <= ushort.MaxValue) + { + useOffset = 3; + } + else + { + useOffset = 5; + } + + encodedBytesOffset = useOffset; + return ref buffer; + } + + /// <summary> + /// Finalizes an encoding of a string. + /// </summary> + /// <param name="pBuffer">A pointer obtained from a prior call to <see cref="WriteString_PrepareSpan"/>.</param> + /// <param name="estimatedOffset">The offset obtained from a prior call to <see cref="WriteString_PrepareSpan"/>.</param> + /// <param name="byteCount">The number of bytes used to actually encode the string.</param> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe void WriteString_PostEncoding(byte* pBuffer, int estimatedOffset, int byteCount) + { + int bufferLength = estimatedOffset + byteCount; + + // move body and write prefix + if (byteCount <= MessagePackRange.MaxFixStringLength) + { + if (estimatedOffset != 1) + { + Buffer.MemoryCopy(pBuffer + estimatedOffset, pBuffer + 1, byteCount, byteCount); + } + pBuffer[0] = (byte)(MessagePackCode.MinFixStr | byteCount); + writer.Advance(byteCount + 1); + } + else if (byteCount <= byte.MaxValue && !this.OldSpec) + { + if (estimatedOffset != 2) + { + Buffer.MemoryCopy(pBuffer + estimatedOffset, pBuffer + 2, byteCount, byteCount); + } + + pBuffer[0] = MessagePackCode.Str8; + pBuffer[1] = unchecked((byte)byteCount); + writer.Advance(byteCount + 2); + } + else if (byteCount <= ushort.MaxValue) + { + if (estimatedOffset != 3) + { + Buffer.MemoryCopy(pBuffer + estimatedOffset, pBuffer + 3, byteCount, byteCount); + } + + pBuffer[0] = MessagePackCode.Str16; + WriteBigEndian((ushort)byteCount, pBuffer + 1); + writer.Advance(byteCount + 3); + } + else + { + if (estimatedOffset != 5) + { + Buffer.MemoryCopy(pBuffer + estimatedOffset, pBuffer + 5, byteCount, byteCount); + } + + pBuffer[0] = MessagePackCode.Str32; + WriteBigEndian((uint)byteCount, pBuffer + 1); + writer.Advance(byteCount + 5); + } + } } } diff --git a/src/MessagePack/StringEncoding.cs b/src/MessagePack/StringEncoding.cs index 318ce955..f7ba9ecf 100644 --- a/src/MessagePack/StringEncoding.cs +++ b/src/MessagePack/StringEncoding.cs @@ -1,4 +1,7 @@ -using System; +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Text; namespace MessagePack @@ -7,20 +10,7 @@ namespace MessagePack { internal static readonly Encoding UTF8 = new UTF8Encoding(false); - internal static unsafe int GetBytes(this Encoding encoding, ReadOnlySpan<char> chars, Span<byte> bytes) - { - if (chars.Length == 0) - { - return 0; - } - - fixed (char* pChars = &chars[0]) - fixed (byte* pBytes = &bytes[0]) - { - return encoding.GetBytes(pChars, chars.Length, pBytes, bytes.Length); - } - } - +#if !NETCOREAPP2_1 // Define the extension method only where an instance method does not already exist. internal static unsafe string GetString(this Encoding encoding, ReadOnlySpan<byte> bytes) { if (bytes.Length == 0) @@ -33,7 +23,6 @@ namespace MessagePack return encoding.GetString(pBytes, bytes.Length); } } - - internal static unsafe int GetBytes(this Encoding encoding, string chars, Span<byte> bytes) => GetBytes(encoding, chars.AsSpan(), bytes); +#endif } } diff --git a/src/MessagePack/Utilities.cs b/src/MessagePack/Utilities.cs index fc471927..607bc1d4 100644 --- a/src/MessagePack/Utilities.cs +++ b/src/MessagePack/Utilities.cs @@ -11,14 +11,30 @@ namespace MessagePack /// </summary> internal static class Utilities { + /// <summary> + /// Writes a sequence to the specified writer. + /// </summary> + /// <param name="source">The sequence to be copied.</param> + /// <param name="writer">The writer to copy to.</param> + internal static void CopyTo(this ReadOnlySequence<byte> source, ref BufferWriter writer) + { + foreach (var segment in source) + { + writer.Write(segment.Span); + } + } + internal delegate void GetWriterBytesAction<TArg>(ref MessagePackWriter writer, TArg argument); internal static byte[] GetWriterBytes<TArg>(TArg arg, GetWriterBytesAction<TArg> action) { - var writer = new MessagePackWriter(); - action(ref writer, arg); - writer.Flush(); - return writer.WrittenBytes.ToArray(); + using (var sequence = new Sequence<byte>()) + { + var writer = new MessagePackWriter(sequence); + action(ref writer, arg); + writer.Flush(); + return sequence.AsReadOnlySequence.ToArray(); + } } } } diff --git a/tests/MessagePack.Tests/FormatterTest.cs b/tests/MessagePack.Tests/FormatterTest.cs index 19b1c828..79ec4c0d 100644 --- a/tests/MessagePack.Tests/FormatterTest.cs +++ b/tests/MessagePack.Tests/FormatterTest.cs @@ -212,30 +212,34 @@ namespace MessagePack.Tests var c = new String('あ', 130); var d = new String('あ', 40000); - var sequenceAWriter = new MessagePackWriter(); + var sequenceA = new Sequence<byte>(); + var sequenceAWriter = new MessagePackWriter(sequenceA); sequenceAWriter.Write(a); sequenceAWriter.Flush(); - sequenceAWriter.WrittenBytes.Length.Is(Encoding.UTF8.GetByteCount(a) + 1); + sequenceA.Length.Is(Encoding.UTF8.GetByteCount(a) + 1); - var sequenceBWriter = new MessagePackWriter(); + var sequenceB = new Sequence<byte>(); + var sequenceBWriter = new MessagePackWriter(sequenceB); sequenceBWriter.Write(b); sequenceBWriter.Flush(); - sequenceBWriter.WrittenBytes.Length.Is(Encoding.UTF8.GetByteCount(b) + 2); + sequenceB.Length.Is(Encoding.UTF8.GetByteCount(b) + 2); - var sequenceCWriter = new MessagePackWriter(); + var sequenceC = new Sequence<byte>(); + var sequenceCWriter = new MessagePackWriter(sequenceC); sequenceCWriter.Write(c); sequenceCWriter.Flush(); - sequenceCWriter.WrittenBytes.Length.Is(Encoding.UTF8.GetByteCount(c) + 3); + sequenceC.Length.Is(Encoding.UTF8.GetByteCount(c) + 3); - var sequenceDWriter = new MessagePackWriter(); + var sequenceD = new Sequence<byte>(); + var sequenceDWriter = new MessagePackWriter(sequenceD); sequenceDWriter.Write(d); sequenceDWriter.Flush(); - sequenceDWriter.WrittenBytes.Length.Is(Encoding.UTF8.GetByteCount(d) + 5); + sequenceD.Length.Is(Encoding.UTF8.GetByteCount(d) + 5); - var readerA = new MessagePackReader(sequenceAWriter.WrittenBytes); - var readerB = new MessagePackReader(sequenceBWriter.WrittenBytes); - var readerC = new MessagePackReader(sequenceCWriter.WrittenBytes); - var readerD = new MessagePackReader(sequenceDWriter.WrittenBytes); + var readerA = new MessagePackReader(sequenceA.AsReadOnlySequence); + var readerB = new MessagePackReader(sequenceB.AsReadOnlySequence); + var readerC = new MessagePackReader(sequenceC.AsReadOnlySequence); + var readerD = new MessagePackReader(sequenceD.AsReadOnlySequence); readerA.ReadString().Is(a); readerB.ReadString().Is(b); readerC.ReadString().Is(c); diff --git a/tests/MessagePack.Tests/MessagePackBinaryTest.cs b/tests/MessagePack.Tests/MessagePackBinaryTest.cs index db0b651f..fe68ec6e 100644 --- a/tests/MessagePack.Tests/MessagePackBinaryTest.cs +++ b/tests/MessagePack.Tests/MessagePackBinaryTest.cs @@ -33,19 +33,20 @@ namespace MessagePack.Tests { (var stream, var packer) = CreateReferencePacker(); - var writer = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var writer = new MessagePackWriter(sequence); writer.WriteNil(); writer.Flush(); - writer.WrittenBytes.Length.Is(1); + sequence.Length.Is(1); - packer.PackNull().Position.Is(writer.WrittenBytes.Length); - stream.ToArray().SequenceEqual(writer.WrittenBytes.ToArray()).IsTrue(); + packer.PackNull().Position.Is(sequence.Length); + stream.ToArray().SequenceEqual(sequence.AsReadOnlySequence.ToArray()).IsTrue(); - var sequenceReader = new MessagePackReader(writer.WrittenBytes); + var sequenceReader = new MessagePackReader(sequence.AsReadOnlySequence); sequenceReader.ReadNil().Is(Nil.Default); sequenceReader.End.IsTrue(); - CreateUnpackedReference(writer.WrittenBytes).IsNil.IsTrue(); + CreateUnpackedReference(sequence).IsNil.IsTrue(); } [Theory] @@ -55,19 +56,20 @@ namespace MessagePack.Tests { (var stream, var packer) = CreateReferencePacker(); - var writer = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var writer = new MessagePackWriter(sequence); writer.Write(target); writer.Flush(); - writer.WrittenBytes.Length.Is(length); + sequence.Length.Is(length); - packer.Pack(target).Position.Is(writer.WrittenBytes.Length); - stream.ToArray().SequenceEqual(writer.WrittenBytes.ToArray()).IsTrue(); + packer.Pack(target).Position.Is(sequence.Length); + stream.ToArray().SequenceEqual(sequence.AsReadOnlySequence.ToArray()).IsTrue(); - var sequenceReader = new MessagePackReader(writer.WrittenBytes); + var sequenceReader = new MessagePackReader(sequence.AsReadOnlySequence); sequenceReader.ReadBoolean().Is(target); sequenceReader.End.IsTrue(); - CreateUnpackedReference(writer.WrittenBytes).AsBoolean().Is(target); + CreateUnpackedReference(sequence).AsBoolean().Is(target); } [Theory] @@ -79,19 +81,20 @@ namespace MessagePack.Tests { (var stream, var packer) = CreateReferencePacker(); - var writer = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var writer = new MessagePackWriter(sequence); writer.Write(target); writer.Flush(); - writer.WrittenBytes.Length.Is(length); + sequence.Length.Is(length); - packer.Pack(target).Position.Is(writer.WrittenBytes.Length); - stream.ToArray().SequenceEqual(writer.WrittenBytes.ToArray()).IsTrue(); + packer.Pack(target).Position.Is(sequence.Length); + stream.ToArray().SequenceEqual(sequence.AsReadOnlySequence.ToArray()).IsTrue(); - var sequenceReader = new MessagePackReader(writer.WrittenBytes); + var sequenceReader = new MessagePackReader(sequence.AsReadOnlySequence); sequenceReader.ReadByte().Is(target); sequenceReader.End.IsTrue(); - CreateUnpackedReference(writer.WrittenBytes).AsByte().Is(target); + CreateUnpackedReference(sequence).AsByte().Is(target); } public static object[][] bytesTestData = new object[][] @@ -109,19 +112,20 @@ namespace MessagePack.Tests { (var stream, var packer) = CreateReferencePacker(); - var writer = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var writer = new MessagePackWriter(sequence); writer.Write(target); writer.Flush(); - writer.WrittenBytes.Length.Is(length); + sequence.Length.Is(length); - packer.PackBinary(target).Position.Is(writer.WrittenBytes.Length); - stream.ToArray().SequenceEqual(writer.WrittenBytes.ToArray()).IsTrue(); + packer.PackBinary(target).Position.Is(sequence.Length); + stream.ToArray().SequenceEqual(sequence.AsReadOnlySequence.ToArray()).IsTrue(); - var sequenceReader = new MessagePackReader(writer.WrittenBytes); + var sequenceReader = new MessagePackReader(sequence.AsReadOnlySequence); sequenceReader.ReadBytes().ToArray().Is(target); sequenceReader.End.IsTrue(); - CreateUnpackedReference(writer.WrittenBytes).AsBinary().Is(target); + CreateUnpackedReference(sequence).AsBinary().Is(target); } [Theory] @@ -140,19 +144,20 @@ namespace MessagePack.Tests { (var stream, var packer) = CreateReferencePacker(); - var writer = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var writer = new MessagePackWriter(sequence); writer.Write(target); writer.Flush(); - writer.WrittenBytes.Length.Is(length); + sequence.Length.Is(length); - packer.Pack(target).Position.Is(writer.WrittenBytes.Length); - stream.ToArray().SequenceEqual(writer.WrittenBytes.ToArray()).IsTrue(); + packer.Pack(target).Position.Is(sequence.Length); + stream.ToArray().SequenceEqual(sequence.AsReadOnlySequence.ToArray()).IsTrue(); - var sequenceReader = new MessagePackReader(writer.WrittenBytes); + var sequenceReader = new MessagePackReader(sequence.AsReadOnlySequence); sequenceReader.ReadSByte().Is(target); sequenceReader.End.IsTrue(); - CreateUnpackedReference(writer.WrittenBytes).AsSByte().Is(target); + CreateUnpackedReference(sequence).AsSByte().Is(target); } [Theory] @@ -169,19 +174,20 @@ namespace MessagePack.Tests { (var stream, var packer) = CreateReferencePacker(); - var writer = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var writer = new MessagePackWriter(sequence); writer.Write(target); writer.Flush(); - writer.WrittenBytes.Length.Is(length); + sequence.Length.Is(length); - packer.Pack(target).Position.Is(writer.WrittenBytes.Length); - stream.ToArray().SequenceEqual(writer.WrittenBytes.ToArray()).IsTrue(); + packer.Pack(target).Position.Is(sequence.Length); + stream.ToArray().SequenceEqual(sequence.AsReadOnlySequence.ToArray()).IsTrue(); - var sequenceReader = new MessagePackReader(writer.WrittenBytes); + var sequenceReader = new MessagePackReader(sequence.AsReadOnlySequence); sequenceReader.ReadSingle().Is(target); sequenceReader.End.IsTrue(); - CreateUnpackedReference(writer.WrittenBytes).AsSingle().Is(target); + CreateUnpackedReference(sequence).AsSingle().Is(target); } [Theory] @@ -198,19 +204,20 @@ namespace MessagePack.Tests { (var stream, var packer) = CreateReferencePacker(); - var writer = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var writer = new MessagePackWriter(sequence); writer.Write(target); writer.Flush(); - writer.WrittenBytes.Length.Is(length); + sequence.Length.Is(length); - packer.Pack(target).Position.Is(writer.WrittenBytes.Length); - stream.ToArray().SequenceEqual(writer.WrittenBytes.ToArray()).IsTrue(); + packer.Pack(target).Position.Is(sequence.Length); + stream.ToArray().SequenceEqual(sequence.AsReadOnlySequence.ToArray()).IsTrue(); - var sequenceReader = new MessagePackReader(writer.WrittenBytes); + var sequenceReader = new MessagePackReader(sequence.AsReadOnlySequence); sequenceReader.ReadDouble().Is(target); sequenceReader.End.IsTrue(); - CreateUnpackedReference(writer.WrittenBytes).AsDouble().Is(target); + CreateUnpackedReference(sequence).AsDouble().Is(target); } [Theory] @@ -233,20 +240,21 @@ namespace MessagePack.Tests { (var stream, var packer) = CreateReferencePacker(); - var writer = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var writer = new MessagePackWriter(sequence); writer.Write(target); writer.Flush(); - writer.WrittenBytes.Length.Is(length); + sequence.Length.Is(length); - packer.Pack(target).Position.Is(writer.WrittenBytes.Length); - // stream.ToArray().SequenceEqual(writer.WrittenBytes.ToArray()).IsTrue(); + packer.Pack(target).Position.Is(sequence.Length); + // stream.ToArray().SequenceEqual(sequence.AsReadOnlySequence.ToArray()).IsTrue(); - var sequenceReader = new MessagePackReader(writer.WrittenBytes); + var sequenceReader = new MessagePackReader(sequence.AsReadOnlySequence); sequenceReader.ReadInt16().Is(target); sequenceReader.End.IsTrue(); - CreateUnpackedReference(writer.WrittenBytes).AsInt16().Is(target); + CreateUnpackedReference(sequence).AsInt16().Is(target); } [Theory] @@ -274,31 +282,32 @@ namespace MessagePack.Tests { (var stream, var packer) = CreateReferencePacker(); - var writer = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var writer = new MessagePackWriter(sequence); writer.Write(target); writer.Flush(); - writer.WrittenBytes.Length.Is(length); + sequence.Length.Is(length); // bug of msgpack-cli if (target == 255) { - packer.Pack((byte)255).Position.Is(writer.WrittenBytes.Length); + packer.Pack((byte)255).Position.Is(sequence.Length); } else if (target == 50000) { - packer.Pack((ushort)50000).Position.Is(writer.WrittenBytes.Length); + packer.Pack((ushort)50000).Position.Is(sequence.Length); } else { - packer.Pack(target).Position.Is(writer.WrittenBytes.Length); + packer.Pack(target).Position.Is(sequence.Length); } - // stream.ToArray().SequenceEqual(writer.WrittenBytes.ToArray()).IsTrue(); + // stream.ToArray().SequenceEqual(sequence.AsReadOnlySequence.ToArray()).IsTrue(); - var sequenceReader = new MessagePackReader(writer.WrittenBytes); + var sequenceReader = new MessagePackReader(sequence.AsReadOnlySequence); sequenceReader.ReadInt32().Is(target); sequenceReader.End.IsTrue(); - CreateUnpackedReference(writer.WrittenBytes).AsInt32().Is(target); + CreateUnpackedReference(sequence).AsInt32().Is(target); } [Theory] @@ -331,35 +340,36 @@ namespace MessagePack.Tests { (var stream, var packer) = CreateReferencePacker(); - var writer = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var writer = new MessagePackWriter(sequence); writer.Write(target); writer.Flush(); - writer.WrittenBytes.Length.Is(length); + sequence.Length.Is(length); // bug of msgpack-cli if (target == 255) { - packer.Pack((byte)255).Position.Is(writer.WrittenBytes.Length); + packer.Pack((byte)255).Position.Is(sequence.Length); } else if (target == 50000) { - packer.Pack((ushort)50000).Position.Is(writer.WrittenBytes.Length); + packer.Pack((ushort)50000).Position.Is(sequence.Length); } else if (target == uint.MaxValue) { - packer.Pack(uint.MaxValue).Position.Is(writer.WrittenBytes.Length); + packer.Pack(uint.MaxValue).Position.Is(sequence.Length); } else { - packer.Pack(target).Position.Is(writer.WrittenBytes.Length); + packer.Pack(target).Position.Is(sequence.Length); } - // stream.ToArray().SequenceEqual(writer.WrittenBytes.ToArray()).IsTrue(); + // stream.ToArray().SequenceEqual(sequence.AsReadOnlySequence.ToArray()).IsTrue(); - var sequenceReader = new MessagePackReader(writer.WrittenBytes); + var sequenceReader = new MessagePackReader(sequence.AsReadOnlySequence); sequenceReader.ReadInt64().Is(target); sequenceReader.End.IsTrue(); - CreateUnpackedReference(writer.WrittenBytes).AsInt64().Is(target); + CreateUnpackedReference(sequence).AsInt64().Is(target); } [Theory] @@ -380,19 +390,20 @@ namespace MessagePack.Tests { (var stream, var packer) = CreateReferencePacker(); - var writer = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var writer = new MessagePackWriter(sequence); writer.WriteMapHeader(target); writer.Flush(); - writer.WrittenBytes.Length.Is(length); + sequence.Length.Is(length); - packer.PackMapHeader((int)target).Position.Is(writer.WrittenBytes.Length); - stream.ToArray().SequenceEqual(writer.WrittenBytes.ToArray()).IsTrue(); + packer.PackMapHeader((int)target).Position.Is(sequence.Length); + stream.ToArray().SequenceEqual(sequence.AsReadOnlySequence.ToArray()).IsTrue(); - var sequenceReader = new MessagePackReader(writer.WrittenBytes); + var sequenceReader = new MessagePackReader(sequence.AsReadOnlySequence); sequenceReader.ReadMapHeader().Is((int)target); sequenceReader.End.IsTrue(); - var ms = new MemoryStream(writer.WrittenBytes.ToArray()); + var ms = new MemoryStream(sequence.AsReadOnlySequence.ToArray()); var unpacker = MsgPack.Unpacker.Create(ms); long len; unpacker.ReadMapLength(out len).IsTrue(); @@ -417,19 +428,20 @@ namespace MessagePack.Tests { (var stream, var packer) = CreateReferencePacker(); - var writer = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var writer = new MessagePackWriter(sequence); writer.WriteArrayHeader(target); writer.Flush(); - writer.WrittenBytes.Length.Is(length); + sequence.Length.Is(length); - packer.PackArrayHeader((int)target).Position.Is(writer.WrittenBytes.Length); - stream.ToArray().SequenceEqual(writer.WrittenBytes.ToArray()).IsTrue(); + packer.PackArrayHeader((int)target).Position.Is(sequence.Length); + stream.ToArray().SequenceEqual(sequence.AsReadOnlySequence.ToArray()).IsTrue(); - var sequenceReader = new MessagePackReader(writer.WrittenBytes); + var sequenceReader = new MessagePackReader(sequence.AsReadOnlySequence); sequenceReader.ReadArrayHeader().Is((int)target); sequenceReader.End.IsTrue(); - var ms = new MemoryStream(writer.WrittenBytes.ToArray()); + var ms = new MemoryStream(sequence.AsReadOnlySequence.ToArray()); var unpacker = MsgPack.Unpacker.Create(ms); long len; unpacker.ReadArrayLength(out len).IsTrue(); @@ -451,19 +463,20 @@ namespace MessagePack.Tests { (var stream, var packer) = CreateReferencePacker(); - var writer = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var writer = new MessagePackWriter(sequence); writer.Write(target); writer.Flush(); - writer.WrittenBytes.Length.Is(length); + sequence.Length.Is(length); - packer.Pack(target).Position.Is(writer.WrittenBytes.Length); - stream.ToArray().SequenceEqual(writer.WrittenBytes.ToArray()).IsTrue(); + packer.Pack(target).Position.Is(sequence.Length); + stream.ToArray().SequenceEqual(sequence.AsReadOnlySequence.ToArray()).IsTrue(); - var sequenceReader = new MessagePackReader(writer.WrittenBytes); + var sequenceReader = new MessagePackReader(sequence.AsReadOnlySequence); sequenceReader.ReadUInt16().Is(target); sequenceReader.End.IsTrue(); - CreateUnpackedReference(writer.WrittenBytes).AsUInt16().Is(target); + CreateUnpackedReference(sequence).AsUInt16().Is(target); } [Theory] @@ -482,19 +495,20 @@ namespace MessagePack.Tests { (var stream, var packer) = CreateReferencePacker(); - var writer = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var writer = new MessagePackWriter(sequence); writer.Write(target); writer.Flush(); - writer.WrittenBytes.Length.Is(length); + sequence.Length.Is(length); - packer.Pack(target).Position.Is(writer.WrittenBytes.Length); - stream.ToArray().SequenceEqual(writer.WrittenBytes.ToArray()).IsTrue(); + packer.Pack(target).Position.Is(sequence.Length); + stream.ToArray().SequenceEqual(sequence.AsReadOnlySequence.ToArray()).IsTrue(); - var sequenceReader = new MessagePackReader(writer.WrittenBytes); + var sequenceReader = new MessagePackReader(sequence.AsReadOnlySequence); sequenceReader.ReadUInt32().Is(target); sequenceReader.End.IsTrue(); - CreateUnpackedReference(writer.WrittenBytes).AsUInt32().Is(target); + CreateUnpackedReference(sequence).AsUInt32().Is(target); } [Theory] @@ -517,19 +531,20 @@ namespace MessagePack.Tests { (var stream, var packer) = CreateReferencePacker(); - var writer = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var writer = new MessagePackWriter(sequence); writer.Write(target); writer.Flush(); - writer.WrittenBytes.Length.Is(length); + sequence.Length.Is(length); - packer.Pack(target).Position.Is(writer.WrittenBytes.Length); - stream.ToArray().SequenceEqual(writer.WrittenBytes.ToArray()).IsTrue(); + packer.Pack(target).Position.Is(sequence.Length); + stream.ToArray().SequenceEqual(sequence.AsReadOnlySequence.ToArray()).IsTrue(); - var sequenceReader = new MessagePackReader(writer.WrittenBytes); + var sequenceReader = new MessagePackReader(sequence.AsReadOnlySequence); sequenceReader.ReadUInt64().Is(target); sequenceReader.End.IsTrue(); - CreateUnpackedReference(writer.WrittenBytes).AsUInt64().Is(target); + CreateUnpackedReference(sequence).AsUInt64().Is(target); } @@ -563,20 +578,21 @@ namespace MessagePack.Tests { (var stream, var packer) = CreateReferencePacker(); - var writer = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var writer = new MessagePackWriter(sequence); writer.Write(target); writer.Flush(); - var returnLength = writer.WrittenBytes.Length; + var returnLength = sequence.Length; var referencePacked = packer.PackString(target); referencePacked.Position.Is(returnLength); - stream.ToArray().SequenceEqual(writer.WrittenBytes.ToArray()).IsTrue(); + stream.ToArray().SequenceEqual(sequence.AsReadOnlySequence.ToArray()).IsTrue(); - var sequenceReader = new MessagePackReader(writer.WrittenBytes); + var sequenceReader = new MessagePackReader(sequence.AsReadOnlySequence); sequenceReader.ReadString().Is(target); sequenceReader.End.IsTrue(); - CreateUnpackedReference(writer.WrittenBytes).AsStringUtf8().Is(target); + CreateUnpackedReference(sequence).AsStringUtf8().Is(target); } [Theory] @@ -585,21 +601,22 @@ namespace MessagePack.Tests { (var stream, var packer) = CreateReferencePacker(); - var writer = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var writer = new MessagePackWriter(sequence); writer.Write(target); writer.Flush(); - var returnLength = writer.WrittenBytes.Length; + var returnLength = sequence.Length; var referencePacked = packer.PackString(target); referencePacked.Position.Is(returnLength); - stream.ToArray().SequenceEqual(writer.WrittenBytes.ToArray()).IsTrue(); + stream.ToArray().SequenceEqual(sequence.AsReadOnlySequence.ToArray()).IsTrue(); - var sequenceReader = new MessagePackReader(writer.WrittenBytes); + var sequenceReader = new MessagePackReader(sequence.AsReadOnlySequence); var segment = sequenceReader.ReadStringSegment().ToArray(); Encoding.UTF8.GetString(segment).Is(target); sequenceReader.End.IsTrue(); - CreateUnpackedReference(writer.WrittenBytes).AsStringUtf8().Is(target); + CreateUnpackedReference(sequence).AsStringUtf8().Is(target); } [Theory] @@ -612,20 +629,21 @@ namespace MessagePack.Tests { (var stream, var packer) = CreateReferencePacker(); - var writer = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var writer = new MessagePackWriter(sequence); writer.Write(target); writer.Flush(); - var returnLength = writer.WrittenBytes.Length; + var returnLength = sequence.Length; var referencePacked = packer.Pack(target); referencePacked.Position.Is(returnLength); - referencePacked.Position.Is(writer.WrittenBytes.Length); - stream.ToArray().SequenceEqual(writer.WrittenBytes.ToArray()).IsTrue(); + referencePacked.Position.Is(sequence.Length); + stream.ToArray().SequenceEqual(sequence.AsReadOnlySequence.ToArray()).IsTrue(); - var sequenceReader = new MessagePackReader(writer.WrittenBytes); + var sequenceReader = new MessagePackReader(sequence.AsReadOnlySequence); sequenceReader.ReadChar().Is(target); sequenceReader.End.IsTrue(); - ((char)CreateUnpackedReference(writer.WrittenBytes).AsUInt16()).Is(target); + ((char)CreateUnpackedReference(sequence).AsUInt16()).Is(target); } @@ -669,23 +687,24 @@ namespace MessagePack.Tests { (var stream, var packer) = CreateReferencePacker(); - var writer = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var writer = new MessagePackWriter(sequence); writer.WriteExtensionFormat(new ExtensionResult(typeCode, target)); writer.Flush(); - var returnLength = writer.WrittenBytes.Length; + var returnLength = sequence.Length; var referencePacked = packer.PackExtendedTypeValue((byte)typeCode, target); referencePacked.Position.Is(returnLength); - referencePacked.Position.Is(writer.WrittenBytes.Length); - stream.ToArray().SequenceEqual(writer.WrittenBytes.ToArray()).IsTrue(); + referencePacked.Position.Is(sequence.Length); + stream.ToArray().SequenceEqual(sequence.AsReadOnlySequence.ToArray()).IsTrue(); - var sequenceReader = new MessagePackReader(writer.WrittenBytes); + var sequenceReader = new MessagePackReader(sequence.AsReadOnlySequence); var ext = sequenceReader.ReadExtensionFormat(); ext.TypeCode.Is(typeCode); ext.Data.ToArray().SequenceEqual(target).IsTrue(); sequenceReader.End.IsTrue(); - var ext2 = CreateUnpackedReference(writer.WrittenBytes).AsMessagePackExtendedTypeObject(); + var ext2 = CreateUnpackedReference(sequence).AsMessagePackExtendedTypeObject(); ext2.TypeCode.Is((byte)ext.TypeCode); ext2.GetBody().SequenceEqual(ext.Data.ToArray()).IsTrue(); } @@ -716,13 +735,14 @@ namespace MessagePack.Tests [MemberData(nameof(dateTimeTestData))] public void DateTimeTest(DateTime target, int expectedLength) { - var writer = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var writer = new MessagePackWriter(sequence); writer.Write(target); writer.Flush(); - var returnLength = writer.WrittenBytes.Length; + var returnLength = sequence.Length; returnLength.Is(expectedLength); - var sequenceReader = new MessagePackReader(writer.WrittenBytes); + var sequenceReader = new MessagePackReader(sequence.AsReadOnlySequence); var result = sequenceReader.ReadDateTime(); sequenceReader.End.IsTrue(); @@ -736,73 +756,85 @@ namespace MessagePack.Tests // Int32 can accepts UInt16 // Int64 can accepts UInt32 { - var smallWriter = new MessagePackWriter(); + var small = new Sequence<byte>(); + var smallWriter = new MessagePackWriter(small); smallWriter.Write(byte.MaxValue); smallWriter.Flush(); - var smallReader = new MessagePackReader(smallWriter.WrittenBytes); + var smallReader = new MessagePackReader(small.AsReadOnlySequence); smallReader.ReadInt16().Is(byte.MaxValue); - var targetWriter = new MessagePackWriter(); + var target = new Sequence<byte>(); + var targetWriter = new MessagePackWriter(target); targetWriter.Write((short)byte.MaxValue); targetWriter.Flush(); - targetWriter.WrittenBytes.ToArray().SequenceEqual(smallWriter.WrittenBytes.ToArray()).IsTrue(); + target.AsReadOnlySequence.ToArray().SequenceEqual(small.AsReadOnlySequence.ToArray()).IsTrue(); } { - var smallWriter = new MessagePackWriter(); + var small = new Sequence<byte>(); + var smallWriter = new MessagePackWriter(small); smallWriter.Write(byte.MaxValue); smallWriter.Flush(); - var smallReader = new MessagePackReader(smallWriter.WrittenBytes); + var smallReader = new MessagePackReader(small.AsReadOnlySequence); smallReader.ReadInt32().Is(byte.MaxValue); - var targetWriter = new MessagePackWriter(); + var target = new Sequence<byte>(); + var targetWriter = new MessagePackWriter(target); targetWriter.Write((int)byte.MaxValue); targetWriter.Flush(); - targetWriter.WrittenBytes.ToArray().SequenceEqual(smallWriter.WrittenBytes.ToArray()).IsTrue(); + target.AsReadOnlySequence.ToArray().SequenceEqual(small.AsReadOnlySequence.ToArray()).IsTrue(); - smallWriter = new MessagePackWriter(); + small.Reset(); + smallWriter = new MessagePackWriter(small); smallWriter.Write(ushort.MaxValue); smallWriter.Flush(); - smallReader = new MessagePackReader(smallWriter.WrittenBytes); + smallReader = new MessagePackReader(small.AsReadOnlySequence); smallReader.ReadInt32().Is(ushort.MaxValue); - targetWriter = new MessagePackWriter(); + target.Reset(); + targetWriter = new MessagePackWriter(target); targetWriter.Write((int)ushort.MaxValue); targetWriter.Flush(); - targetWriter.WrittenBytes.ToArray().SequenceEqual(smallWriter.WrittenBytes.ToArray()).IsTrue(); + target.AsReadOnlySequence.ToArray().SequenceEqual(small.AsReadOnlySequence.ToArray()).IsTrue(); } { - var smallWriter = new MessagePackWriter(); + var small = new Sequence<byte>(); + var smallWriter = new MessagePackWriter(small); smallWriter.Write(byte.MaxValue); smallWriter.Flush(); - var smallReader = new MessagePackReader(smallWriter.WrittenBytes); + var smallReader = new MessagePackReader(small.AsReadOnlySequence); smallReader.ReadInt64().Is(byte.MaxValue); - var targetWriter = new MessagePackWriter(); + var target = new Sequence<byte>(); + var targetWriter = new MessagePackWriter(target); targetWriter.Write((long)byte.MaxValue); targetWriter.Flush(); - targetWriter.WrittenBytes.ToArray().SequenceEqual(smallWriter.WrittenBytes.ToArray()).IsTrue(); + target.AsReadOnlySequence.ToArray().SequenceEqual(small.AsReadOnlySequence.ToArray()).IsTrue(); - smallWriter = new MessagePackWriter(); + small.Reset(); + smallWriter = new MessagePackWriter(small); smallWriter.Write(ushort.MaxValue); smallWriter.Flush(); - smallReader = new MessagePackReader(smallWriter.WrittenBytes); + smallReader = new MessagePackReader(small.AsReadOnlySequence); smallReader.ReadInt64().Is(ushort.MaxValue); - targetWriter = new MessagePackWriter(); + target.Reset(); + targetWriter = new MessagePackWriter(target); targetWriter.Write((long)ushort.MaxValue); targetWriter.Flush(); - targetWriter.WrittenBytes.ToArray().SequenceEqual(smallWriter.WrittenBytes.ToArray()).IsTrue(); + target.AsReadOnlySequence.ToArray().SequenceEqual(small.AsReadOnlySequence.ToArray()).IsTrue(); - smallWriter = new MessagePackWriter(); + small.Reset(); + smallWriter = new MessagePackWriter(small); smallWriter.Write(uint.MaxValue); smallWriter.Flush(); - smallReader = new MessagePackReader(smallWriter.WrittenBytes); + smallReader = new MessagePackReader(small.AsReadOnlySequence); smallReader.ReadInt64().Is(uint.MaxValue); - targetWriter = new MessagePackWriter(); + target.Reset(); + targetWriter = new MessagePackWriter(target); targetWriter.Write((long)uint.MaxValue); targetWriter.Flush(); - targetWriter.WrittenBytes.ToArray().SequenceEqual(smallWriter.WrittenBytes.ToArray()).IsTrue(); + target.AsReadOnlySequence.ToArray().SequenceEqual(small.AsReadOnlySequence.ToArray()).IsTrue(); } } } diff --git a/tests/MessagePack.Tests/MessagePackReaderTests.ReadInt.cs b/tests/MessagePack.Tests/MessagePackReaderTests.ReadInt.cs index fada4148..3f91a31a 100644 --- a/tests/MessagePack.Tests/MessagePackReaderTests.ReadInt.cs +++ b/tests/MessagePack.Tests/MessagePackReaderTests.ReadInt.cs @@ -2,6 +2,7 @@ // CHANGE THE .tt FILE INSTEAD. using System; +using System.Buffers; using System.Collections.Generic; using System.Numerics; using Xunit; @@ -13,129 +14,129 @@ namespace MessagePack.Tests private const sbyte MinNegativeFixInt = unchecked((sbyte)MessagePackCode.MinNegativeFixInt); private const sbyte MaxNegativeFixInt = unchecked((sbyte)MessagePackCode.MaxNegativeFixInt); - private readonly IReadOnlyList<(BigInteger Value, ReadOnlyMemory<byte> Encoded)> IntegersOfInterest = new List<(BigInteger Value, ReadOnlyMemory<byte> Encoded)> + private readonly IReadOnlyList<(BigInteger Value, ReadOnlySequence<byte> Encoded)> IntegersOfInterest = new List<(BigInteger Value, ReadOnlySequence<byte> Encoded)> { // * FixInt // ** non-boundary - (3, Encode(b => MessagePackBinary.WriteByte(ref b, 0, 3))), - (3, Encode(b => MessagePackBinary.WriteByteForceByteBlock(ref b, 0, 3))), - (3, Encode(b => MessagePackBinary.WriteUInt16ForceUInt16Block(ref b, 0, 3))), - (3, Encode(b => MessagePackBinary.WriteUInt32ForceUInt32Block(ref b, 0, 3))), - (3, Encode(b => MessagePackBinary.WriteUInt64ForceUInt64Block(ref b, 0, 3))), - (3, Encode(b => MessagePackBinary.WriteSByteForceSByteBlock(ref b, 0, 3))), - (3, Encode(b => MessagePackBinary.WriteInt16ForceInt16Block(ref b, 0, 3))), - (3, Encode(b => MessagePackBinary.WriteInt32ForceInt32Block(ref b, 0, 3))), - (3, Encode(b => MessagePackBinary.WriteInt64ForceInt64Block(ref b, 0, 3))), + (3, Encode((ref MessagePackWriter w) => w.WriteByte(3))), + (3, Encode((ref MessagePackWriter w) => w.WriteByte(3))), + (3, Encode((ref MessagePackWriter w) => w.WriteUInt16(3))), + (3, Encode((ref MessagePackWriter w) => w.WriteUInt32(3))), + (3, Encode((ref MessagePackWriter w) => w.WriteUInt64(3))), + (3, Encode((ref MessagePackWriter w) => w.WriteSByte(3))), + (3, Encode((ref MessagePackWriter w) => w.WriteInt16(3))), + (3, Encode((ref MessagePackWriter w) => w.WriteInt32(3))), + (3, Encode((ref MessagePackWriter w) => w.WriteInt64(3))), - (-3, Encode(b => MessagePackBinary.WriteSByte(ref b, 0, -3))), - (-3, Encode(b => MessagePackBinary.WriteSByteForceSByteBlock(ref b, 0, -3))), - (-3, Encode(b => MessagePackBinary.WriteInt16ForceInt16Block(ref b, 0, -3))), - (-3, Encode(b => MessagePackBinary.WriteInt32ForceInt32Block(ref b, 0, -3))), - (-3, Encode(b => MessagePackBinary.WriteInt64ForceInt64Block(ref b, 0, -3))), + (-3, Encode((ref MessagePackWriter w) => w.WriteSByte(-3))), + (-3, Encode((ref MessagePackWriter w) => w.WriteSByte(-3))), + (-3, Encode((ref MessagePackWriter w) => w.WriteInt16(-3))), + (-3, Encode((ref MessagePackWriter w) => w.WriteInt32(-3))), + (-3, Encode((ref MessagePackWriter w) => w.WriteInt64(-3))), // ** Boundary conditions // *** MaxFixInt - (MessagePackCode.MaxFixInt, Encode(b => MessagePackBinary.WriteByte(ref b, 0, MessagePackCode.MaxFixInt))), - (MessagePackCode.MaxFixInt, Encode(b => MessagePackBinary.WriteByteForceByteBlock(ref b, 0, checked((Byte)MessagePackCode.MaxFixInt)))), - (MessagePackCode.MaxFixInt, Encode(b => MessagePackBinary.WriteUInt16ForceUInt16Block(ref b, 0, checked((UInt16)MessagePackCode.MaxFixInt)))), - (MessagePackCode.MaxFixInt, Encode(b => MessagePackBinary.WriteUInt32ForceUInt32Block(ref b, 0, checked((UInt32)MessagePackCode.MaxFixInt)))), - (MessagePackCode.MaxFixInt, Encode(b => MessagePackBinary.WriteUInt64ForceUInt64Block(ref b, 0, checked((UInt64)MessagePackCode.MaxFixInt)))), - (MessagePackCode.MaxFixInt, Encode(b => MessagePackBinary.WriteSByteForceSByteBlock(ref b, 0, checked((SByte)MessagePackCode.MaxFixInt)))), - (MessagePackCode.MaxFixInt, Encode(b => MessagePackBinary.WriteInt16ForceInt16Block(ref b, 0, checked((Int16)MessagePackCode.MaxFixInt)))), - (MessagePackCode.MaxFixInt, Encode(b => MessagePackBinary.WriteInt32ForceInt32Block(ref b, 0, checked((Int32)MessagePackCode.MaxFixInt)))), - (MessagePackCode.MaxFixInt, Encode(b => MessagePackBinary.WriteInt64ForceInt64Block(ref b, 0, checked((Int64)MessagePackCode.MaxFixInt)))), + (MessagePackCode.MaxFixInt, Encode((ref MessagePackWriter w) => w.WriteByte(MessagePackCode.MaxFixInt))), + (MessagePackCode.MaxFixInt, Encode((ref MessagePackWriter w) => w.WriteByte(checked((Byte)MessagePackCode.MaxFixInt)))), + (MessagePackCode.MaxFixInt, Encode((ref MessagePackWriter w) => w.WriteUInt16(checked((UInt16)MessagePackCode.MaxFixInt)))), + (MessagePackCode.MaxFixInt, Encode((ref MessagePackWriter w) => w.WriteUInt32(checked((UInt32)MessagePackCode.MaxFixInt)))), + (MessagePackCode.MaxFixInt, Encode((ref MessagePackWriter w) => w.WriteUInt64(checked((UInt64)MessagePackCode.MaxFixInt)))), + (MessagePackCode.MaxFixInt, Encode((ref MessagePackWriter w) => w.WriteSByte(checked((SByte)MessagePackCode.MaxFixInt)))), + (MessagePackCode.MaxFixInt, Encode((ref MessagePackWriter w) => w.WriteInt16(checked((Int16)MessagePackCode.MaxFixInt)))), + (MessagePackCode.MaxFixInt, Encode((ref MessagePackWriter w) => w.WriteInt32(checked((Int32)MessagePackCode.MaxFixInt)))), + (MessagePackCode.MaxFixInt, Encode((ref MessagePackWriter w) => w.WriteInt64(checked((Int64)MessagePackCode.MaxFixInt)))), // *** MinFixInt - (MessagePackCode.MinFixInt, Encode(b => MessagePackBinary.WriteByte(ref b, 0, MessagePackCode.MinFixInt))), - (MessagePackCode.MinFixInt, Encode(b => MessagePackBinary.WriteByteForceByteBlock(ref b, 0, checked((Byte)MessagePackCode.MinFixInt)))), - (MessagePackCode.MinFixInt, Encode(b => MessagePackBinary.WriteUInt16ForceUInt16Block(ref b, 0, checked((UInt16)MessagePackCode.MinFixInt)))), - (MessagePackCode.MinFixInt, Encode(b => MessagePackBinary.WriteUInt32ForceUInt32Block(ref b, 0, checked((UInt32)MessagePackCode.MinFixInt)))), - (MessagePackCode.MinFixInt, Encode(b => MessagePackBinary.WriteUInt64ForceUInt64Block(ref b, 0, checked((UInt64)MessagePackCode.MinFixInt)))), - (MessagePackCode.MinFixInt, Encode(b => MessagePackBinary.WriteSByteForceSByteBlock(ref b, 0, checked((SByte)MessagePackCode.MinFixInt)))), - (MessagePackCode.MinFixInt, Encode(b => MessagePackBinary.WriteInt16ForceInt16Block(ref b, 0, checked((Int16)MessagePackCode.MinFixInt)))), - (MessagePackCode.MinFixInt, Encode(b => MessagePackBinary.WriteInt32ForceInt32Block(ref b, 0, checked((Int32)MessagePackCode.MinFixInt)))), - (MessagePackCode.MinFixInt, Encode(b => MessagePackBinary.WriteInt64ForceInt64Block(ref b, 0, checked((Int64)MessagePackCode.MinFixInt)))), + (MessagePackCode.MinFixInt, Encode((ref MessagePackWriter w) => w.WriteByte(MessagePackCode.MinFixInt))), + (MessagePackCode.MinFixInt, Encode((ref MessagePackWriter w) => w.WriteByte(checked((Byte)MessagePackCode.MinFixInt)))), + (MessagePackCode.MinFixInt, Encode((ref MessagePackWriter w) => w.WriteUInt16(checked((UInt16)MessagePackCode.MinFixInt)))), + (MessagePackCode.MinFixInt, Encode((ref MessagePackWriter w) => w.WriteUInt32(checked((UInt32)MessagePackCode.MinFixInt)))), + (MessagePackCode.MinFixInt, Encode((ref MessagePackWriter w) => w.WriteUInt64(checked((UInt64)MessagePackCode.MinFixInt)))), + (MessagePackCode.MinFixInt, Encode((ref MessagePackWriter w) => w.WriteSByte(checked((SByte)MessagePackCode.MinFixInt)))), + (MessagePackCode.MinFixInt, Encode((ref MessagePackWriter w) => w.WriteInt16(checked((Int16)MessagePackCode.MinFixInt)))), + (MessagePackCode.MinFixInt, Encode((ref MessagePackWriter w) => w.WriteInt32(checked((Int32)MessagePackCode.MinFixInt)))), + (MessagePackCode.MinFixInt, Encode((ref MessagePackWriter w) => w.WriteInt64(checked((Int64)MessagePackCode.MinFixInt)))), // *** MinNegativeFixInt - (MinNegativeFixInt, Encode(b => MessagePackBinary.WriteSByteForceSByteBlock(ref b, 0, MinNegativeFixInt))), - (MinNegativeFixInt, Encode(b => MessagePackBinary.WriteInt16ForceInt16Block(ref b, 0, MinNegativeFixInt))), - (MinNegativeFixInt, Encode(b => MessagePackBinary.WriteInt32ForceInt32Block(ref b, 0, MinNegativeFixInt))), - (MinNegativeFixInt, Encode(b => MessagePackBinary.WriteInt64ForceInt64Block(ref b, 0, MinNegativeFixInt))), + (MinNegativeFixInt, Encode((ref MessagePackWriter w) => w.WriteSByte(MinNegativeFixInt))), + (MinNegativeFixInt, Encode((ref MessagePackWriter w) => w.WriteInt16(MinNegativeFixInt))), + (MinNegativeFixInt, Encode((ref MessagePackWriter w) => w.WriteInt32(MinNegativeFixInt))), + (MinNegativeFixInt, Encode((ref MessagePackWriter w) => w.WriteInt64(MinNegativeFixInt))), // *** MaxNegativeFixInt - (MaxNegativeFixInt, Encode(b => MessagePackBinary.WriteSByteForceSByteBlock(ref b, 0, MaxNegativeFixInt))), - (MaxNegativeFixInt, Encode(b => MessagePackBinary.WriteInt16ForceInt16Block(ref b, 0, MaxNegativeFixInt))), - (MaxNegativeFixInt, Encode(b => MessagePackBinary.WriteInt32ForceInt32Block(ref b, 0, MaxNegativeFixInt))), - (MaxNegativeFixInt, Encode(b => MessagePackBinary.WriteInt64ForceInt64Block(ref b, 0, MaxNegativeFixInt))), + (MaxNegativeFixInt, Encode((ref MessagePackWriter w) => w.WriteSByte(MaxNegativeFixInt))), + (MaxNegativeFixInt, Encode((ref MessagePackWriter w) => w.WriteInt16(MaxNegativeFixInt))), + (MaxNegativeFixInt, Encode((ref MessagePackWriter w) => w.WriteInt32(MaxNegativeFixInt))), + (MaxNegativeFixInt, Encode((ref MessagePackWriter w) => w.WriteInt64(MaxNegativeFixInt))), - (MessagePackCode.MaxFixInt, Encode(b => MessagePackBinary.WriteInt32(ref b, 0, MessagePackCode.MaxFixInt))), - (MessagePackCode.MinFixInt, Encode(b => MessagePackBinary.WriteInt32(ref b, 0, MessagePackCode.MinFixInt))), - (MaxNegativeFixInt, Encode(b => MessagePackBinary.WriteInt32(ref b, 0, MaxNegativeFixInt))), - (MinNegativeFixInt, Encode(b => MessagePackBinary.WriteInt32(ref b, 0, MinNegativeFixInt))), + (MessagePackCode.MaxFixInt, Encode((ref MessagePackWriter w) => w.WriteInt32(MessagePackCode.MaxFixInt))), + (MessagePackCode.MinFixInt, Encode((ref MessagePackWriter w) => w.WriteInt32(MessagePackCode.MinFixInt))), + (MaxNegativeFixInt, Encode((ref MessagePackWriter w) => w.WriteInt32(MaxNegativeFixInt))), + (MinNegativeFixInt, Encode((ref MessagePackWriter w) => w.WriteInt32(MinNegativeFixInt))), // * Encoded as each type of at least 8 bits // ** Small positive value - (3, Encode(b => MessagePackBinary.WriteByteForceByteBlock(ref b, 0, 3))), - (3, Encode(b => MessagePackBinary.WriteUInt16ForceUInt16Block(ref b, 0, 3))), - (3, Encode(b => MessagePackBinary.WriteUInt32ForceUInt32Block(ref b, 0, 3))), - (3, Encode(b => MessagePackBinary.WriteUInt64ForceUInt64Block(ref b, 0, 3))), - (3, Encode(b => MessagePackBinary.WriteSByteForceSByteBlock(ref b, 0, 3))), - (3, Encode(b => MessagePackBinary.WriteInt16ForceInt16Block(ref b, 0, 3))), - (3, Encode(b => MessagePackBinary.WriteInt32ForceInt32Block(ref b, 0, 3))), - (3, Encode(b => MessagePackBinary.WriteInt64ForceInt64Block(ref b, 0, 3))), + (3, Encode((ref MessagePackWriter w) => w.WriteByte(3))), + (3, Encode((ref MessagePackWriter w) => w.WriteUInt16(3))), + (3, Encode((ref MessagePackWriter w) => w.WriteUInt32(3))), + (3, Encode((ref MessagePackWriter w) => w.WriteUInt64(3))), + (3, Encode((ref MessagePackWriter w) => w.WriteSByte(3))), + (3, Encode((ref MessagePackWriter w) => w.WriteInt16(3))), + (3, Encode((ref MessagePackWriter w) => w.WriteInt32(3))), + (3, Encode((ref MessagePackWriter w) => w.WriteInt64(3))), // ** Small negative value - (-3, Encode(b => MessagePackBinary.WriteSByteForceSByteBlock(ref b, 0, -3))), - (-3, Encode(b => MessagePackBinary.WriteInt16ForceInt16Block(ref b, 0, -3))), - (-3, Encode(b => MessagePackBinary.WriteInt32ForceInt32Block(ref b, 0, -3))), - (-3, Encode(b => MessagePackBinary.WriteInt64ForceInt64Block(ref b, 0, -3))), + (-3, Encode((ref MessagePackWriter w) => w.WriteSByte(-3))), + (-3, Encode((ref MessagePackWriter w) => w.WriteInt16(-3))), + (-3, Encode((ref MessagePackWriter w) => w.WriteInt32(-3))), + (-3, Encode((ref MessagePackWriter w) => w.WriteInt64(-3))), // ** Max values // *** Positive - (0x0ff, Encode(b => MessagePackBinary.WriteByteForceByteBlock(ref b, 0, 255))), - (0x0ff, Encode(b => MessagePackBinary.WriteUInt16ForceUInt16Block(ref b, 0, 255))), - (0x0ff, Encode(b => MessagePackBinary.WriteUInt32ForceUInt32Block(ref b, 0, 255))), - (0x0ff, Encode(b => MessagePackBinary.WriteUInt64ForceUInt64Block(ref b, 0, 255))), - (0x0ff, Encode(b => MessagePackBinary.WriteInt16ForceInt16Block(ref b, 0, 255))), - (0x0ff, Encode(b => MessagePackBinary.WriteInt32ForceInt32Block(ref b, 0, 255))), - (0x0ff, Encode(b => MessagePackBinary.WriteInt64ForceInt64Block(ref b, 0, 255))), - (0x0ffff, Encode(b => MessagePackBinary.WriteUInt16ForceUInt16Block(ref b, 0, 65535))), - (0x0ffff, Encode(b => MessagePackBinary.WriteUInt32ForceUInt32Block(ref b, 0, 65535))), - (0x0ffff, Encode(b => MessagePackBinary.WriteUInt64ForceUInt64Block(ref b, 0, 65535))), - (0x0ffff, Encode(b => MessagePackBinary.WriteInt32ForceInt32Block(ref b, 0, 65535))), - (0x0ffff, Encode(b => MessagePackBinary.WriteInt64ForceInt64Block(ref b, 0, 65535))), - (0x0ffffffff, Encode(b => MessagePackBinary.WriteUInt32ForceUInt32Block(ref b, 0, 4294967295))), - (0x0ffffffff, Encode(b => MessagePackBinary.WriteUInt64ForceUInt64Block(ref b, 0, 4294967295))), - (0x0ffffffff, Encode(b => MessagePackBinary.WriteInt64ForceInt64Block(ref b, 0, 4294967295))), - (0x0ffffffffffffffff, Encode(b => MessagePackBinary.WriteUInt64ForceUInt64Block(ref b, 0, 18446744073709551615))), - (0x7f, Encode(b => MessagePackBinary.WriteByteForceByteBlock(ref b, 0, 127))), - (0x7f, Encode(b => MessagePackBinary.WriteUInt16ForceUInt16Block(ref b, 0, 127))), - (0x7f, Encode(b => MessagePackBinary.WriteUInt32ForceUInt32Block(ref b, 0, 127))), - (0x7f, Encode(b => MessagePackBinary.WriteUInt64ForceUInt64Block(ref b, 0, 127))), - (0x7f, Encode(b => MessagePackBinary.WriteSByteForceSByteBlock(ref b, 0, 127))), - (0x7f, Encode(b => MessagePackBinary.WriteInt16ForceInt16Block(ref b, 0, 127))), - (0x7f, Encode(b => MessagePackBinary.WriteInt32ForceInt32Block(ref b, 0, 127))), - (0x7f, Encode(b => MessagePackBinary.WriteInt64ForceInt64Block(ref b, 0, 127))), - (0x7fff, Encode(b => MessagePackBinary.WriteUInt16ForceUInt16Block(ref b, 0, 32767))), - (0x7fff, Encode(b => MessagePackBinary.WriteUInt32ForceUInt32Block(ref b, 0, 32767))), - (0x7fff, Encode(b => MessagePackBinary.WriteUInt64ForceUInt64Block(ref b, 0, 32767))), - (0x7fff, Encode(b => MessagePackBinary.WriteInt16ForceInt16Block(ref b, 0, 32767))), - (0x7fff, Encode(b => MessagePackBinary.WriteInt32ForceInt32Block(ref b, 0, 32767))), - (0x7fff, Encode(b => MessagePackBinary.WriteInt64ForceInt64Block(ref b, 0, 32767))), - (0x7fffffff, Encode(b => MessagePackBinary.WriteUInt32ForceUInt32Block(ref b, 0, 2147483647))), - (0x7fffffff, Encode(b => MessagePackBinary.WriteUInt64ForceUInt64Block(ref b, 0, 2147483647))), - (0x7fffffff, Encode(b => MessagePackBinary.WriteInt32ForceInt32Block(ref b, 0, 2147483647))), - (0x7fffffff, Encode(b => MessagePackBinary.WriteInt64ForceInt64Block(ref b, 0, 2147483647))), - (0x7fffffffffffffff, Encode(b => MessagePackBinary.WriteUInt64ForceUInt64Block(ref b, 0, 9223372036854775807))), - (0x7fffffffffffffff, Encode(b => MessagePackBinary.WriteInt64ForceInt64Block(ref b, 0, 9223372036854775807))), + (0x0ff, Encode((ref MessagePackWriter w) => w.WriteByte(255))), + (0x0ff, Encode((ref MessagePackWriter w) => w.WriteUInt16(255))), + (0x0ff, Encode((ref MessagePackWriter w) => w.WriteUInt32(255))), + (0x0ff, Encode((ref MessagePackWriter w) => w.WriteUInt64(255))), + (0x0ff, Encode((ref MessagePackWriter w) => w.WriteInt16(255))), + (0x0ff, Encode((ref MessagePackWriter w) => w.WriteInt32(255))), + (0x0ff, Encode((ref MessagePackWriter w) => w.WriteInt64(255))), + (0x0ffff, Encode((ref MessagePackWriter w) => w.WriteUInt16(65535))), + (0x0ffff, Encode((ref MessagePackWriter w) => w.WriteUInt32(65535))), + (0x0ffff, Encode((ref MessagePackWriter w) => w.WriteUInt64(65535))), + (0x0ffff, Encode((ref MessagePackWriter w) => w.WriteInt32(65535))), + (0x0ffff, Encode((ref MessagePackWriter w) => w.WriteInt64(65535))), + (0x0ffffffff, Encode((ref MessagePackWriter w) => w.WriteUInt32(4294967295))), + (0x0ffffffff, Encode((ref MessagePackWriter w) => w.WriteUInt64(4294967295))), + (0x0ffffffff, Encode((ref MessagePackWriter w) => w.WriteInt64(4294967295))), + (0x0ffffffffffffffff, Encode((ref MessagePackWriter w) => w.WriteUInt64(18446744073709551615))), + (0x7f, Encode((ref MessagePackWriter w) => w.WriteByte(127))), + (0x7f, Encode((ref MessagePackWriter w) => w.WriteUInt16(127))), + (0x7f, Encode((ref MessagePackWriter w) => w.WriteUInt32(127))), + (0x7f, Encode((ref MessagePackWriter w) => w.WriteUInt64(127))), + (0x7f, Encode((ref MessagePackWriter w) => w.WriteSByte(127))), + (0x7f, Encode((ref MessagePackWriter w) => w.WriteInt16(127))), + (0x7f, Encode((ref MessagePackWriter w) => w.WriteInt32(127))), + (0x7f, Encode((ref MessagePackWriter w) => w.WriteInt64(127))), + (0x7fff, Encode((ref MessagePackWriter w) => w.WriteUInt16(32767))), + (0x7fff, Encode((ref MessagePackWriter w) => w.WriteUInt32(32767))), + (0x7fff, Encode((ref MessagePackWriter w) => w.WriteUInt64(32767))), + (0x7fff, Encode((ref MessagePackWriter w) => w.WriteInt16(32767))), + (0x7fff, Encode((ref MessagePackWriter w) => w.WriteInt32(32767))), + (0x7fff, Encode((ref MessagePackWriter w) => w.WriteInt64(32767))), + (0x7fffffff, Encode((ref MessagePackWriter w) => w.WriteUInt32(2147483647))), + (0x7fffffff, Encode((ref MessagePackWriter w) => w.WriteUInt64(2147483647))), + (0x7fffffff, Encode((ref MessagePackWriter w) => w.WriteInt32(2147483647))), + (0x7fffffff, Encode((ref MessagePackWriter w) => w.WriteInt64(2147483647))), + (0x7fffffffffffffff, Encode((ref MessagePackWriter w) => w.WriteUInt64(9223372036854775807))), + (0x7fffffffffffffff, Encode((ref MessagePackWriter w) => w.WriteInt64(9223372036854775807))), // *** Negative - (unchecked((SByte)0x80), Encode(b => MessagePackBinary.WriteSByteForceSByteBlock(ref b, 0, -128))), - (unchecked((SByte)0x80), Encode(b => MessagePackBinary.WriteInt16ForceInt16Block(ref b, 0, -128))), - (unchecked((SByte)0x80), Encode(b => MessagePackBinary.WriteInt32ForceInt32Block(ref b, 0, -128))), - (unchecked((SByte)0x80), Encode(b => MessagePackBinary.WriteInt64ForceInt64Block(ref b, 0, -128))), - (unchecked((Int16)0x8000), Encode(b => MessagePackBinary.WriteInt16ForceInt16Block(ref b, 0, -32768))), - (unchecked((Int16)0x8000), Encode(b => MessagePackBinary.WriteInt32ForceInt32Block(ref b, 0, -32768))), - (unchecked((Int16)0x8000), Encode(b => MessagePackBinary.WriteInt64ForceInt64Block(ref b, 0, -32768))), - (unchecked((Int32)0x80000000), Encode(b => MessagePackBinary.WriteInt32ForceInt32Block(ref b, 0, -2147483648))), - (unchecked((Int32)0x80000000), Encode(b => MessagePackBinary.WriteInt64ForceInt64Block(ref b, 0, -2147483648))), - (unchecked((Int64)0x8000000000000000), Encode(b => MessagePackBinary.WriteInt64ForceInt64Block(ref b, 0, -9223372036854775808))), + (unchecked((SByte)0x80), Encode((ref MessagePackWriter w) => w.WriteSByte(-128))), + (unchecked((SByte)0x80), Encode((ref MessagePackWriter w) => w.WriteInt16(-128))), + (unchecked((SByte)0x80), Encode((ref MessagePackWriter w) => w.WriteInt32(-128))), + (unchecked((SByte)0x80), Encode((ref MessagePackWriter w) => w.WriteInt64(-128))), + (unchecked((Int16)0x8000), Encode((ref MessagePackWriter w) => w.WriteInt16(-32768))), + (unchecked((Int16)0x8000), Encode((ref MessagePackWriter w) => w.WriteInt32(-32768))), + (unchecked((Int16)0x8000), Encode((ref MessagePackWriter w) => w.WriteInt64(-32768))), + (unchecked((Int32)0x80000000), Encode((ref MessagePackWriter w) => w.WriteInt32(-2147483648))), + (unchecked((Int32)0x80000000), Encode((ref MessagePackWriter w) => w.WriteInt64(-2147483648))), + (unchecked((Int64)0x8000000000000000), Encode((ref MessagePackWriter w) => w.WriteInt64(-9223372036854775808))), }; [Fact] @@ -143,7 +144,7 @@ namespace MessagePack.Tests { foreach (var (value, encoded) in IntegersOfInterest) { - this.logger.WriteLine("Decoding 0x{0:x} from {1}", value, MessagePackCode.ToFormatName(encoded.Span[0])); + this.logger.WriteLine("Decoding 0x{0:x} from {1}", value, MessagePackCode.ToFormatName(encoded.First.Span[0])); if (value <= Byte.MaxValue && value >= Byte.MinValue) { Assert.Equal(value, new MessagePackReader(encoded).ReadByte()); @@ -166,7 +167,7 @@ namespace MessagePack.Tests { foreach (var (value, encoded) in IntegersOfInterest) { - this.logger.WriteLine("Decoding 0x{0:x} from {1}", value, MessagePackCode.ToFormatName(encoded.Span[0])); + this.logger.WriteLine("Decoding 0x{0:x} from {1}", value, MessagePackCode.ToFormatName(encoded.First.Span[0])); if (value <= UInt16.MaxValue && value >= UInt16.MinValue) { Assert.Equal(value, new MessagePackReader(encoded).ReadUInt16()); @@ -189,7 +190,7 @@ namespace MessagePack.Tests { foreach (var (value, encoded) in IntegersOfInterest) { - this.logger.WriteLine("Decoding 0x{0:x} from {1}", value, MessagePackCode.ToFormatName(encoded.Span[0])); + this.logger.WriteLine("Decoding 0x{0:x} from {1}", value, MessagePackCode.ToFormatName(encoded.First.Span[0])); if (value <= UInt32.MaxValue && value >= UInt32.MinValue) { Assert.Equal(value, new MessagePackReader(encoded).ReadUInt32()); @@ -212,7 +213,7 @@ namespace MessagePack.Tests { foreach (var (value, encoded) in IntegersOfInterest) { - this.logger.WriteLine("Decoding 0x{0:x} from {1}", value, MessagePackCode.ToFormatName(encoded.Span[0])); + this.logger.WriteLine("Decoding 0x{0:x} from {1}", value, MessagePackCode.ToFormatName(encoded.First.Span[0])); if (value <= UInt64.MaxValue && value >= UInt64.MinValue) { Assert.Equal(value, new MessagePackReader(encoded).ReadUInt64()); @@ -235,7 +236,7 @@ namespace MessagePack.Tests { foreach (var (value, encoded) in IntegersOfInterest) { - this.logger.WriteLine("Decoding 0x{0:x} from {1}", value, MessagePackCode.ToFormatName(encoded.Span[0])); + this.logger.WriteLine("Decoding 0x{0:x} from {1}", value, MessagePackCode.ToFormatName(encoded.First.Span[0])); if (value <= SByte.MaxValue && value >= SByte.MinValue) { Assert.Equal(value, new MessagePackReader(encoded).ReadSByte()); @@ -258,7 +259,7 @@ namespace MessagePack.Tests { foreach (var (value, encoded) in IntegersOfInterest) { - this.logger.WriteLine("Decoding 0x{0:x} from {1}", value, MessagePackCode.ToFormatName(encoded.Span[0])); + this.logger.WriteLine("Decoding 0x{0:x} from {1}", value, MessagePackCode.ToFormatName(encoded.First.Span[0])); if (value <= Int16.MaxValue && value >= Int16.MinValue) { Assert.Equal(value, new MessagePackReader(encoded).ReadInt16()); @@ -281,7 +282,7 @@ namespace MessagePack.Tests { foreach (var (value, encoded) in IntegersOfInterest) { - this.logger.WriteLine("Decoding 0x{0:x} from {1}", value, MessagePackCode.ToFormatName(encoded.Span[0])); + this.logger.WriteLine("Decoding 0x{0:x} from {1}", value, MessagePackCode.ToFormatName(encoded.First.Span[0])); if (value <= Int32.MaxValue && value >= Int32.MinValue) { Assert.Equal(value, new MessagePackReader(encoded).ReadInt32()); @@ -304,7 +305,7 @@ namespace MessagePack.Tests { foreach (var (value, encoded) in IntegersOfInterest) { - this.logger.WriteLine("Decoding 0x{0:x} from {1}", value, MessagePackCode.ToFormatName(encoded.Span[0])); + this.logger.WriteLine("Decoding 0x{0:x} from {1}", value, MessagePackCode.ToFormatName(encoded.First.Span[0])); if (value <= Int64.MaxValue && value >= Int64.MinValue) { Assert.Equal(value, new MessagePackReader(encoded).ReadInt64()); diff --git a/tests/MessagePack.Tests/MessagePackReaderTests.ReadInt.tt b/tests/MessagePack.Tests/MessagePackReaderTests.ReadInt.tt index 72b61e5b..373255b6 100644 --- a/tests/MessagePack.Tests/MessagePackReaderTests.ReadInt.tt +++ b/tests/MessagePack.Tests/MessagePackReaderTests.ReadInt.tt @@ -6,6 +6,7 @@ // CHANGE THE .tt FILE INSTEAD. using System; +using System.Buffers; using System.Collections.Generic; using System.Numerics; using Xunit; @@ -38,54 +39,54 @@ string GetMinValue(Type intType) => $"0x{intType.GetField(nameof(int.MinValue)). private const sbyte MinNegativeFixInt = unchecked((sbyte)MessagePackCode.MinNegativeFixInt); private const sbyte MaxNegativeFixInt = unchecked((sbyte)MessagePackCode.MaxNegativeFixInt); - private readonly IReadOnlyList<(BigInteger Value, ReadOnlyMemory<byte> Encoded)> IntegersOfInterest = new List<(BigInteger Value, ReadOnlyMemory<byte> Encoded)> + private readonly IReadOnlyList<(BigInteger Value, ReadOnlySequence<byte> Encoded)> IntegersOfInterest = new List<(BigInteger Value, ReadOnlySequence<byte> Encoded)> { // * FixInt // ** non-boundary - (3, Encode(b => MessagePackBinary.WriteByte(ref b, 0, 3))), + (3, Encode((ref MessagePackWriter w) => w.WriteByte(3))), <# foreach (Type type in allTypes) { #> - (3, Encode(b => MessagePackBinary.Write<#=type.Name#>Force<#=type.Name#>Block(ref b, 0, 3))), + (3, Encode((ref MessagePackWriter w) => w.Write<#=type.Name#>(3))), <# } #> - (-3, Encode(b => MessagePackBinary.WriteSByte(ref b, 0, -3))), + (-3, Encode((ref MessagePackWriter w) => w.WriteSByte(-3))), <# foreach (Type type in signedTypes) { #> - (-3, Encode(b => MessagePackBinary.Write<#=type.Name#>Force<#=type.Name#>Block(ref b, 0, -3))), + (-3, Encode((ref MessagePackWriter w) => w.Write<#=type.Name#>(-3))), <# } #> // ** Boundary conditions // *** MaxFixInt - (MessagePackCode.MaxFixInt, Encode(b => MessagePackBinary.WriteByte(ref b, 0, MessagePackCode.MaxFixInt))), + (MessagePackCode.MaxFixInt, Encode((ref MessagePackWriter w) => w.WriteByte(MessagePackCode.MaxFixInt))), <# foreach (Type type in allTypes) { #> - (MessagePackCode.MaxFixInt, Encode(b => MessagePackBinary.Write<#=type.Name#>Force<#=type.Name#>Block(ref b, 0, checked((<#=type.Name#>)MessagePackCode.MaxFixInt)))), + (MessagePackCode.MaxFixInt, Encode((ref MessagePackWriter w) => w.Write<#=type.Name#>(checked((<#=type.Name#>)MessagePackCode.MaxFixInt)))), <# } #> // *** MinFixInt - (MessagePackCode.MinFixInt, Encode(b => MessagePackBinary.WriteByte(ref b, 0, MessagePackCode.MinFixInt))), + (MessagePackCode.MinFixInt, Encode((ref MessagePackWriter w) => w.WriteByte(MessagePackCode.MinFixInt))), <# foreach (Type type in allTypes) { #> - (MessagePackCode.MinFixInt, Encode(b => MessagePackBinary.Write<#=type.Name#>Force<#=type.Name#>Block(ref b, 0, checked((<#=type.Name#>)MessagePackCode.MinFixInt)))), + (MessagePackCode.MinFixInt, Encode((ref MessagePackWriter w) => w.Write<#=type.Name#>(checked((<#=type.Name#>)MessagePackCode.MinFixInt)))), <# } #> // *** MinNegativeFixInt <# foreach (Type type in signedTypes) { #> - (MinNegativeFixInt, Encode(b => MessagePackBinary.Write<#=type.Name#>Force<#=type.Name#>Block(ref b, 0, MinNegativeFixInt))), + (MinNegativeFixInt, Encode((ref MessagePackWriter w) => w.Write<#=type.Name#>(MinNegativeFixInt))), <# } #> // *** MaxNegativeFixInt <# foreach (Type type in signedTypes) { #> - (MaxNegativeFixInt, Encode(b => MessagePackBinary.Write<#=type.Name#>Force<#=type.Name#>Block(ref b, 0, MaxNegativeFixInt))), + (MaxNegativeFixInt, Encode((ref MessagePackWriter w) => w.Write<#=type.Name#>(MaxNegativeFixInt))), <# } #> - (MessagePackCode.MaxFixInt, Encode(b => MessagePackBinary.WriteInt32(ref b, 0, MessagePackCode.MaxFixInt))), - (MessagePackCode.MinFixInt, Encode(b => MessagePackBinary.WriteInt32(ref b, 0, MessagePackCode.MinFixInt))), - (MaxNegativeFixInt, Encode(b => MessagePackBinary.WriteInt32(ref b, 0, MaxNegativeFixInt))), - (MinNegativeFixInt, Encode(b => MessagePackBinary.WriteInt32(ref b, 0, MinNegativeFixInt))), + (MessagePackCode.MaxFixInt, Encode((ref MessagePackWriter w) => w.WriteInt32(MessagePackCode.MaxFixInt))), + (MessagePackCode.MinFixInt, Encode((ref MessagePackWriter w) => w.WriteInt32(MessagePackCode.MinFixInt))), + (MaxNegativeFixInt, Encode((ref MessagePackWriter w) => w.WriteInt32(MaxNegativeFixInt))), + (MinNegativeFixInt, Encode((ref MessagePackWriter w) => w.WriteInt32(MinNegativeFixInt))), // * Encoded as each type of at least 8 bits // ** Small positive value <# foreach (Type t1 in allTypes) { #> - (3, Encode(b => MessagePackBinary.Write<#=t1.Name#>Force<#=t1.Name#>Block(ref b, 0, 3))), + (3, Encode((ref MessagePackWriter w) => w.Write<#=t1.Name#>(3))), <# } #> // ** Small negative value <# foreach (Type t1 in signedTypes) { #> - (-3, Encode(b => MessagePackBinary.Write<#=t1.Name#>Force<#=t1.Name#>Block(ref b, 0, -3))), + (-3, Encode((ref MessagePackWriter w) => w.Write<#=t1.Name#>(-3))), <# } #> // ** Max values @@ -94,7 +95,7 @@ string GetMinValue(Type intType) => $"0x{intType.GetField(nameof(int.MinValue)). var maxValue = GetMaxValueAsInt(typeForMaxValue); foreach (var encodedType in allTypes) { if (GetMaxValueAsInt(encodedType) >= maxValue) { #> - (0x<#=maxValue.ToString("x")#>, Encode(b => MessagePackBinary.Write<#=encodedType.Name#>Force<#=encodedType.Name#>Block(ref b, 0, <#=maxValue#>))), + (0x<#=maxValue.ToString("x")#>, Encode((ref MessagePackWriter w) => w.Write<#=encodedType.Name#>(<#=maxValue#>))), <# } } } #> @@ -103,7 +104,7 @@ string GetMinValue(Type intType) => $"0x{intType.GetField(nameof(int.MinValue)). var minValue = GetMinValueAsInt(typeForMinValue); foreach (var encodedType in signedTypes) { if (GetMinValueAsInt(encodedType) <= minValue) { #> - (unchecked((<#=typeForMinValue.Name#>)0x<#=minValue.ToString("x")#>), Encode(b => MessagePackBinary.Write<#=encodedType.Name#>Force<#=encodedType.Name#>Block(ref b, 0, <#=minValue#>))), + (unchecked((<#=typeForMinValue.Name#>)0x<#=minValue.ToString("x")#>), Encode((ref MessagePackWriter w) => w.Write<#=encodedType.Name#>(<#=minValue#>))), <# } } } #> @@ -115,7 +116,7 @@ string GetMinValue(Type intType) => $"0x{intType.GetField(nameof(int.MinValue)). { foreach (var (value, encoded) in IntegersOfInterest) { - this.logger.WriteLine("Decoding 0x{0:x} from {1}", value, MessagePackCode.ToFormatName(encoded.Span[0])); + this.logger.WriteLine("Decoding 0x{0:x} from {1}", value, MessagePackCode.ToFormatName(encoded.First.Span[0])); if (value <= <#=t1.Name#>.MaxValue && value >= <#=t1.Name#>.MinValue) { Assert.Equal(value, new MessagePackReader(encoded).Read<#=t1.Name#>()); diff --git a/tests/MessagePack.Tests/MessagePackReaderTests.cs b/tests/MessagePack.Tests/MessagePackReaderTests.cs index a7cc7ca4..b43f7bee 100644 --- a/tests/MessagePack.Tests/MessagePackReaderTests.cs +++ b/tests/MessagePack.Tests/MessagePackReaderTests.cs @@ -1,5 +1,6 @@ using System; -using System.Numerics; +using System.Buffers; +using Nerdbank.Streams; using Xunit; using Xunit.Abstractions; @@ -9,7 +10,7 @@ namespace MessagePack.Tests { private const sbyte ByteNegativeValue = -3; private const byte BytePositiveValue = 3; - private static readonly ReadOnlyMemory<byte> StringEncodedAsFixStr = Encode(b => MessagePackBinary.WriteString(ref b, 0, "hi")); + private static readonly ReadOnlySequence<byte> StringEncodedAsFixStr = Encode((ref MessagePackWriter w) => w.Write("hi")); private readonly ITestOutputHelper logger; public MessagePackReaderTests(ITestOutputHelper logger) @@ -22,7 +23,7 @@ namespace MessagePack.Tests { foreach (var (value, encoded) in IntegersOfInterest) { - this.logger.WriteLine("Decoding 0x{0:x} from {1}", value, MessagePackCode.ToFormatName(encoded.Span[0])); + this.logger.WriteLine("Decoding 0x{0:x} from {1}", value, MessagePackCode.ToFormatName(encoded.First.Span[0])); Assert.Equal((float)(double)value, new MessagePackReader(encoded).ReadSingle()); } } @@ -30,15 +31,25 @@ namespace MessagePack.Tests [Fact] public void ReadSingle_CanReadDouble() { - var reader = new MessagePackReader(Encode(b => MessagePackBinary.WriteDouble(ref b, 0, 1.23))); + var reader = new MessagePackReader(Encode((ref MessagePackWriter w) => w.Write(1.23))); Assert.Equal(1.23f, reader.ReadSingle()); } - private static ReadOnlyMemory<byte> Encode(Func<byte[], int> writer) + private delegate void WriterEncoder(ref MessagePackWriter writer); + + private static ReadOnlySequence<byte> Encode(WriterEncoder cb) { - byte[] bytes = new byte[100]; - int byteCount = writer(bytes); - return bytes.AsMemory(0, byteCount); + var sequence = new Sequence<byte>(); + var writer = new MessagePackWriter(sequence); + cb(ref writer); + writer.Flush(); + return sequence.AsReadOnlySequence; } } + + internal static class MessagePackWriterExtensions + { + internal static void WriteByte(ref this MessagePackWriter writer, byte value) => writer.WriteUInt8(value); + internal static void WriteSByte(ref this MessagePackWriter writer, sbyte value) => writer.WriteInt8(value); + } } diff --git a/tests/MessagePack.Tests/NewGuidFormatterTest.cs b/tests/MessagePack.Tests/NewGuidFormatterTest.cs index dba87b68..11259414 100644 --- a/tests/MessagePack.Tests/NewGuidFormatterTest.cs +++ b/tests/MessagePack.Tests/NewGuidFormatterTest.cs @@ -43,12 +43,13 @@ namespace MessagePack.Tests { { var original = Guid.NewGuid(); - var sequenceWriter = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var sequenceWriter = new MessagePackWriter(sequence); GuidFormatter.Instance.Serialize(ref sequenceWriter, original, null); sequenceWriter.Flush(); - sequenceWriter.WrittenBytes.Length.Is(38); + sequence.Length.Is(38); - var sequenceReader = new MessagePackReader(sequenceWriter.WrittenBytes); + var sequenceReader = new MessagePackReader(sequence.AsReadOnlySequence); GuidFormatter.Instance.Deserialize(ref sequenceReader, null).Is(original); sequenceReader.End.IsTrue(); } diff --git a/tests/MessagePack.Tests/OldSpecBinaryFormatterTest.cs b/tests/MessagePack.Tests/OldSpecBinaryFormatterTest.cs index 5ee55c5b..d4062399 100644 --- a/tests/MessagePack.Tests/OldSpecBinaryFormatterTest.cs +++ b/tests/MessagePack.Tests/OldSpecBinaryFormatterTest.cs @@ -23,12 +23,13 @@ namespace MessagePack.Tests public void SerializeSimpleByteArray(int arrayLength) { var sourceBytes = Enumerable.Range(0, arrayLength).Select(i => unchecked((byte)i)).ToArray(); // long byte array - var messagePackBytesWriter = new MessagePackWriter() { OldSpec = true }; + var messagePackBytes = new Sequence<byte>(); + var messagePackBytesWriter = new MessagePackWriter(messagePackBytes) { OldSpec = true }; serializer.Serialize(ref messagePackBytesWriter, sourceBytes); messagePackBytesWriter.Flush(); - Assert.NotEqual(0, messagePackBytesWriter.WrittenBytes.Length); + Assert.NotEqual(0, messagePackBytes.Length); - var deserializedBytes = DeserializeByClassicMsgPack<byte[]>(messagePackBytesWriter.WrittenBytes.ToArray(), MsgPack.Serialization.SerializationMethod.Array); + var deserializedBytes = DeserializeByClassicMsgPack<byte[]>(messagePackBytes.AsReadOnlySequence.ToArray(), MsgPack.Serialization.SerializationMethod.Array); Assert.Equal(sourceBytes, deserializedBytes); } @@ -36,13 +37,14 @@ namespace MessagePack.Tests public void SerializeNil() { byte[] sourceBytes = null; - var messagePackBytesWriter = new MessagePackWriter() { OldSpec = true }; + var messagePackBytes = new Sequence<byte>(); + var messagePackBytesWriter = new MessagePackWriter(messagePackBytes) { OldSpec = true }; serializer.Serialize(ref messagePackBytesWriter, sourceBytes, StandardResolver.Instance); messagePackBytesWriter.Flush(); - Assert.Equal(1, messagePackBytesWriter.WrittenBytes.Length); - Assert.Equal(MessagePackCode.Nil, messagePackBytesWriter.WrittenBytes.First.Span[0]); + Assert.Equal(1, messagePackBytes.Length); + Assert.Equal(MessagePackCode.Nil, messagePackBytes.AsReadOnlySequence.First.Span[0]); - var deserializedBytes = DeserializeByClassicMsgPack<byte[]>(messagePackBytesWriter.WrittenBytes.ToArray(), MsgPack.Serialization.SerializationMethod.Array); + var deserializedBytes = DeserializeByClassicMsgPack<byte[]>(messagePackBytes.AsReadOnlySequence.ToArray(), MsgPack.Serialization.SerializationMethod.Array); Assert.Null(deserializedBytes); } diff --git a/tests/MessagePack.Tests/PrimitivelikeFormatterTest.cs b/tests/MessagePack.Tests/PrimitivelikeFormatterTest.cs index bfa0139e..87e9d747 100644 --- a/tests/MessagePack.Tests/PrimitivelikeFormatterTest.cs +++ b/tests/MessagePack.Tests/PrimitivelikeFormatterTest.cs @@ -1,12 +1,12 @@ -using System; +using MessagePack.Formatters; +using MessagePack.Resolvers; +using Nerdbank.Streams; +using System; using System.Buffers; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using MessagePack.Formatters; -using MessagePack.Resolvers; -using Nerdbank.Streams; using Xunit; namespace MessagePack.Tests @@ -94,19 +94,22 @@ namespace MessagePack.Tests var serializer = referenceContext.GetSerializer<string>(); - var oldSpecWriter = new MessagePackWriter() { OldSpec = true }; - defaultSerializer.Serialize(ref oldSpecWriter, data); - oldSpecWriter.Flush(); - var a = oldSpecWriter.WrittenBytes.ToArray(); - var b = serializer.PackSingleObject(data); + using (var sequence = new Sequence<byte>()) + { + var oldSpecWriter = new MessagePackWriter(sequence) { OldSpec = true }; + defaultSerializer.Serialize(ref oldSpecWriter, data); + oldSpecWriter.Flush(); + var a = sequence.AsReadOnlySequence.ToArray(); + var b = serializer.PackSingleObject(data); - a.Is(b); + a.Is(b); - var oldSpecReader = new MessagePackReader(oldSpecWriter.WrittenBytes); - var r1 = defaultSerializer.Deserialize<string>(ref oldSpecReader); - var r2 = serializer.UnpackSingleObject(b); + var oldSpecReader = new MessagePackReader(sequence.AsReadOnlySequence); + var r1 = defaultSerializer.Deserialize<string>(ref oldSpecReader); + var r2 = serializer.UnpackSingleObject(b); - r1.Is(r2); + r1.Is(r2); + } } @@ -122,19 +125,22 @@ namespace MessagePack.Tests var serializer = referenceContext.GetSerializer<byte[]>(); - var oldSpecWriter = new MessagePackWriter() { OldSpec = true }; - defaultSerializer.Serialize(ref oldSpecWriter, data); - oldSpecWriter.Flush(); - var a = oldSpecWriter.WrittenBytes.ToArray(); - var b = serializer.PackSingleObject(data); + using (var sequence = new Sequence<byte>()) + { + var oldSpecWriter = new MessagePackWriter(sequence) { OldSpec = true }; + defaultSerializer.Serialize(ref oldSpecWriter, data); + oldSpecWriter.Flush(); + var a = sequence.AsReadOnlySequence.ToArray(); + var b = serializer.PackSingleObject(data); - a.Is(b); + a.Is(b); - var oldSpecReader = new MessagePackReader(oldSpecWriter.WrittenBytes); - var r1 = defaultSerializer.Deserialize<byte[]>(ref oldSpecReader); - var r2 = serializer.UnpackSingleObject(b); + var oldSpecReader = new MessagePackReader(sequence.AsReadOnlySequence); + var r1 = defaultSerializer.Deserialize<byte[]>(ref oldSpecReader); + var r2 = serializer.UnpackSingleObject(b); - r1.Is(r2); + r1.Is(r2); + } } } } diff --git a/tests/MessagePack.Tests/ToJsonTest.cs b/tests/MessagePack.Tests/ToJsonTest.cs index 3260bb26..7e56f40f 100644 --- a/tests/MessagePack.Tests/ToJsonTest.cs +++ b/tests/MessagePack.Tests/ToJsonTest.cs @@ -15,10 +15,11 @@ namespace MessagePack.Tests string JsonConvert(string json, MessagePackSerializer serializer) { - var sequenceWriter = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var sequenceWriter = new MessagePackWriter(sequence); serializer.ConvertFromJson(json, ref sequenceWriter); sequenceWriter.Flush(); - return serializer.ConvertToJson(sequenceWriter.WrittenBytes); + return serializer.ConvertToJson(sequence.AsReadOnlySequence); } [Theory] diff --git a/tests/MessagePack.Tests/UnsafeFormattersTest.cs b/tests/MessagePack.Tests/UnsafeFormattersTest.cs index 8de392a8..5d8f67f3 100644 --- a/tests/MessagePack.Tests/UnsafeFormattersTest.cs +++ b/tests/MessagePack.Tests/UnsafeFormattersTest.cs @@ -15,12 +15,13 @@ namespace MessagePack.Tests public void GuidTest() { var guid = Guid.NewGuid(); - var sequenceWriter = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var sequenceWriter = new MessagePackWriter(sequence); BinaryGuidFormatter.Instance.Serialize(ref sequenceWriter, guid, null); sequenceWriter.Flush(); - sequenceWriter.WrittenBytes.Length.Is(18); + sequence.Length.Is(18); - var sequenceReader = new MessagePackReader(sequenceWriter.WrittenBytes); + var sequenceReader = new MessagePackReader(sequence.AsReadOnlySequence); var nguid = BinaryGuidFormatter.Instance.Deserialize(ref sequenceReader, null); Assert.True(sequenceReader.End); @@ -31,12 +32,13 @@ namespace MessagePack.Tests public void DecimalTest() { var d = new Decimal(1341, 53156, 61, true, 3); - var sequenceWriter = new MessagePackWriter(); + var sequence = new Sequence<byte>(); + var sequenceWriter = new MessagePackWriter(sequence); BinaryDecimalFormatter.Instance.Serialize(ref sequenceWriter, d, null); sequenceWriter.Flush(); - sequenceWriter.WrittenBytes.Length.Is(18); + sequence.Length.Is(18); - var sequenceReader = new MessagePackReader(sequenceWriter.WrittenBytes); + var sequenceReader = new MessagePackReader(sequence.AsReadOnlySequence); var nd = BinaryDecimalFormatter.Instance.Deserialize(ref sequenceReader, null); Assert.True(sequenceReader.End); diff --git a/tests/MessagePack.Tests/UnsafeMemoryTest.cs b/tests/MessagePack.Tests/UnsafeMemoryTest.cs index d29a9526..56e107e8 100644 --- a/tests/MessagePack.Tests/UnsafeMemoryTest.cs +++ b/tests/MessagePack.Tests/UnsafeMemoryTest.cs @@ -1,4 +1,6 @@ -using MessagePack.Internal; +using MessagePack.Formatters; +using MessagePack.Internal; +using Nerdbank.Streams; using System; using System.Buffers; using System.Collections.Generic; @@ -28,12 +30,13 @@ namespace MessagePack.Tests var s = new string(c, count); var bin1 = CodeGenHelpers.GetEncodedStringBytes(s); var bin2 = serializer.Serialize(s); - var bin3Writer = new MessagePackWriter(); + var bin3 = new Sequence<byte>(); + var bin3Writer = new MessagePackWriter(bin3); bin3Writer.WriteRaw(bin1); bin3Writer.Flush(); MessagePack.Internal.ByteArrayComparer.Equals(bin1, bin2).IsTrue(); - MessagePack.Internal.ByteArrayComparer.Equals(bin1, CodeGenHelpers.GetSpanFromSequence(bin3Writer.WrittenBytes)).IsTrue(); + MessagePack.Internal.ByteArrayComparer.Equals(bin1, CodeGenHelpers.GetSpanFromSequence(bin3)).IsTrue(); } [Fact] @@ -43,21 +46,23 @@ namespace MessagePack.Tests for (int i = 1; i <= MessagePackRange.MaxFixStringLength; i++) { var src = Enumerable.Range(0, i).Select(x => (byte)x).ToArray(); - var dstWriter = new MessagePackWriter(); + var dst = new Sequence<byte>(); + var dstWriter = new MessagePackWriter(dst); ((typeof(UnsafeMemory32).GetMethod("WriteRaw" + i)).CreateDelegate(typeof(WriteDelegate)) as WriteDelegate).Invoke(ref dstWriter, src); dstWriter.Flush(); - dstWriter.WrittenBytes.Length.Is(i); - MessagePack.Internal.ByteArrayComparer.Equals(src, CodeGenHelpers.GetSpanFromSequence(dstWriter.WrittenBytes)).IsTrue(); + dst.Length.Is(i); + MessagePack.Internal.ByteArrayComparer.Equals(src, CodeGenHelpers.GetSpanFromSequence(dst.AsReadOnlySequence)).IsTrue(); } // x64 for (int i = 1; i <= MessagePackRange.MaxFixStringLength; i++) { var src = Enumerable.Range(0, i).Select(x => (byte)x).ToArray(); - var dstWriter = new MessagePackWriter(); + var dst = new Sequence<byte>(); + var dstWriter = new MessagePackWriter(dst); ((typeof(UnsafeMemory64).GetMethod("WriteRaw" + i)).CreateDelegate(typeof(WriteDelegate)) as WriteDelegate).Invoke(ref dstWriter, src); dstWriter.Flush(); - dstWriter.WrittenBytes.Length.Is(i); - MessagePack.Internal.ByteArrayComparer.Equals(src, CodeGenHelpers.GetSpanFromSequence(dstWriter.WrittenBytes)).IsTrue(); + dst.Length.Is(i); + MessagePack.Internal.ByteArrayComparer.Equals(src, CodeGenHelpers.GetSpanFromSequence(dst.AsReadOnlySequence)).IsTrue(); } } } |