using MessagePack.Internal; using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Text; #if NETSTANDARD using System.Threading.Tasks; #endif namespace MessagePack.Formatters { // NET40 -> BigInteger, Complex, Tuple // byte[] is special. represents bin type. public sealed class ByteArrayFormatter : IMessagePackFormatter { public static readonly ByteArrayFormatter Instance = new ByteArrayFormatter(); ByteArrayFormatter() { } public int Serialize(ref byte[] bytes, int offset, byte[] value, IFormatterResolver formatterResolver) { return MessagePackBinary.WriteBytes(ref bytes, offset, value); } public byte[] Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { return MessagePackBinary.ReadBytes(bytes, offset, out readSize); } } public sealed class NullableStringFormatter : IMessagePackFormatter { public static readonly NullableStringFormatter Instance = new NullableStringFormatter(); NullableStringFormatter() { } public int Serialize(ref byte[] bytes, int offset, String value, IFormatterResolver typeResolver) { return MessagePackBinary.WriteString(ref bytes, offset, value); } public String Deserialize(byte[] bytes, int offset, IFormatterResolver typeResolver, out int readSize) { return MessagePackBinary.ReadString(bytes, offset, out readSize); } } public sealed class NullableStringArrayFormatter : IMessagePackFormatter { public static readonly NullableStringArrayFormatter Instance = new NullableStringArrayFormatter(); NullableStringArrayFormatter() { } public int Serialize(ref byte[] bytes, int offset, String[] value, IFormatterResolver typeResolver) { if (value == null) { return MessagePackBinary.WriteNil(ref bytes, offset); } else { var startOffset = offset; offset += MessagePackBinary.WriteArrayHeader(ref bytes, offset, value.Length); for (int i = 0; i < value.Length; i++) { offset += MessagePackBinary.WriteString(ref bytes, offset, value[i]); } return offset - startOffset; } } public String[] Deserialize(byte[] bytes, int offset, IFormatterResolver typeResolver, out int readSize) { if (MessagePackBinary.IsNil(bytes, offset)) { readSize = 1; return null; } else { var startOffset = offset; var len = MessagePackBinary.ReadArrayHeader(bytes, offset, out readSize); offset += readSize; var array = new String[len]; for (int i = 0; i < array.Length; i++) { array[i] = MessagePackBinary.ReadString(bytes, offset, out readSize); offset += readSize; } readSize = offset - startOffset; return array; } } } public sealed class DecimalFormatter : IMessagePackFormatter { public static readonly DecimalFormatter Instance = new DecimalFormatter(); DecimalFormatter() { } public int Serialize(ref byte[] bytes, int offset, decimal value, IFormatterResolver formatterResolver) { return MessagePackBinary.WriteString(ref bytes, offset, value.ToString(CultureInfo.InvariantCulture)); } public decimal Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { return decimal.Parse(MessagePackBinary.ReadString(bytes, offset, out readSize), CultureInfo.InvariantCulture); } } public sealed class TimeSpanFormatter : IMessagePackFormatter { public static readonly IMessagePackFormatter Instance = new TimeSpanFormatter(); TimeSpanFormatter() { } public int Serialize(ref byte[] bytes, int offset, TimeSpan value, IFormatterResolver formatterResolver) { return MessagePackBinary.WriteInt64(ref bytes, offset, value.Ticks); } public TimeSpan Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { return new TimeSpan(MessagePackBinary.ReadInt64(bytes, offset, out readSize)); } } public sealed class DateTimeOffsetFormatter : IMessagePackFormatter { public static readonly IMessagePackFormatter Instance = new DateTimeOffsetFormatter(); DateTimeOffsetFormatter() { } public int Serialize(ref byte[] bytes, int offset, DateTimeOffset value, IFormatterResolver formatterResolver) { var startOffset = offset; offset += MessagePackBinary.WriteArrayHeader(ref bytes, offset, 2); offset += MessagePackBinary.WriteDateTime(ref bytes, offset, new DateTime(value.Ticks, DateTimeKind.Utc)); // current ticks as is offset += MessagePackBinary.WriteInt16(ref bytes, offset, (short)value.Offset.TotalMinutes); // offset is normalized in minutes return offset - startOffset; } public DateTimeOffset Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { var startOffset = offset; var count = MessagePackBinary.ReadArrayHeader(bytes, offset, out readSize); offset += readSize; if (count != 2) throw new InvalidOperationException("Invalid DateTimeOffset format."); var utc = MessagePackBinary.ReadDateTime(bytes, offset, out readSize); offset += readSize; var dtOffsetMinutes = MessagePackBinary.ReadInt16(bytes, offset, out readSize); offset += readSize; readSize = offset - startOffset; return new DateTimeOffset(utc.Ticks, TimeSpan.FromMinutes(dtOffsetMinutes)); } } public sealed class GuidFormatter : IMessagePackFormatter { public static readonly IMessagePackFormatter Instance = new GuidFormatter(); GuidFormatter() { } public int Serialize(ref byte[] bytes, int offset, Guid value, IFormatterResolver formatterResolver) { MessagePackBinary.EnsureCapacity(ref bytes, offset, 38); bytes[offset] = MessagePackCode.Str8; bytes[offset + 1] = unchecked((byte)36); new GuidBits(ref value).Write(bytes, offset + 2); return 38; } public Guid Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { var segment = MessagePackBinary.ReadStringSegment(bytes, offset, out readSize); return new GuidBits(segment).Value; } } public sealed class UriFormatter : IMessagePackFormatter { public static readonly IMessagePackFormatter Instance = new UriFormatter(); UriFormatter() { } public int Serialize(ref byte[] bytes, int offset, Uri value, IFormatterResolver formatterResolver) { if (value == null) { return MessagePackBinary.WriteNil(ref bytes, offset); } else { return MessagePackBinary.WriteString(ref bytes, offset, value.ToString()); } } public Uri Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { if (MessagePackBinary.IsNil(bytes, offset)) { readSize = 1; return null; } else { return new Uri(MessagePackBinary.ReadString(bytes, offset, out readSize), UriKind.RelativeOrAbsolute); } } } public sealed class VersionFormatter : IMessagePackFormatter { public static readonly IMessagePackFormatter Instance = new VersionFormatter(); VersionFormatter() { } public int Serialize(ref byte[] bytes, int offset, Version value, IFormatterResolver formatterResolver) { if (value == null) { return MessagePackBinary.WriteNil(ref bytes, offset); } else { return MessagePackBinary.WriteString(ref bytes, offset, value.ToString()); } } public Version Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { if (MessagePackBinary.IsNil(bytes, offset)) { readSize = 1; return null; } else { return new Version(MessagePackBinary.ReadString(bytes, offset, out readSize)); } } } public sealed class KeyValuePairFormatter : IMessagePackFormatter> { public int Serialize(ref byte[] bytes, int offset, KeyValuePair value, IFormatterResolver formatterResolver) { var startOffset = offset; offset += MessagePackBinary.WriteArrayHeader(ref bytes, offset, 2); offset += formatterResolver.GetFormatterWithVerify().Serialize(ref bytes, offset, value.Key, formatterResolver); offset += formatterResolver.GetFormatterWithVerify().Serialize(ref bytes, offset, value.Value, formatterResolver); return offset - startOffset; } public KeyValuePair Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { var startOffset = offset; var count = MessagePackBinary.ReadArrayHeader(bytes, offset, out readSize); offset += readSize; if (count != 2) throw new InvalidOperationException("Invalid KeyValuePair format."); var key = formatterResolver.GetFormatterWithVerify().Deserialize(bytes, offset, formatterResolver, out readSize); offset += readSize; var value = formatterResolver.GetFormatterWithVerify().Deserialize(bytes, offset, formatterResolver, out readSize); offset += readSize; readSize = offset - startOffset; return new KeyValuePair(key, value); } } public sealed class StringBuilderFormatter : IMessagePackFormatter { public static readonly IMessagePackFormatter Instance = new StringBuilderFormatter(); StringBuilderFormatter() { } public int Serialize(ref byte[] bytes, int offset, StringBuilder value, IFormatterResolver formatterResolver) { if (value == null) { return MessagePackBinary.WriteNil(ref bytes, offset); } else { return MessagePackBinary.WriteString(ref bytes, offset, value.ToString()); } } public StringBuilder Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { if (MessagePackBinary.IsNil(bytes, offset)) { readSize = 1; return null; } else { return new StringBuilder(MessagePackBinary.ReadString(bytes, offset, out readSize)); } } } public sealed class BitArrayFormatter : IMessagePackFormatter { public static readonly IMessagePackFormatter Instance = new BitArrayFormatter(); BitArrayFormatter() { } public int Serialize(ref byte[] bytes, int offset, BitArray value, IFormatterResolver formatterResolver) { if (value == null) { return MessagePackBinary.WriteNil(ref bytes, offset); } else { var startOffset = offset; var len = value.Length; offset += MessagePackBinary.WriteArrayHeader(ref bytes, offset, len); for (int i = 0; i < len; i++) { offset += MessagePackBinary.WriteBoolean(ref bytes, offset, value.Get(i)); } return offset - startOffset; } } public BitArray Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { if (MessagePackBinary.IsNil(bytes, offset)) { readSize = 1; return null; } else { var startOffset = offset; var len = MessagePackBinary.ReadArrayHeader(bytes, offset, out readSize); offset += readSize; var array = new BitArray(len); for (int i = 0; i < len; i++) { array[i] = MessagePackBinary.ReadBoolean(bytes, offset, out readSize); offset += readSize; } readSize = offset - startOffset; return array; } } } #if NETSTANDARD public sealed class BigIntegerFormatter : IMessagePackFormatter { public static readonly IMessagePackFormatter Instance = new BigIntegerFormatter(); BigIntegerFormatter() { } public int Serialize(ref byte[] bytes, int offset, System.Numerics.BigInteger value, IFormatterResolver formatterResolver) { return MessagePackBinary.WriteBytes(ref bytes, offset, value.ToByteArray()); } public System.Numerics.BigInteger Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { return new System.Numerics.BigInteger(MessagePackBinary.ReadBytes(bytes, offset, out readSize)); } } public sealed class ComplexFormatter : IMessagePackFormatter { public static readonly IMessagePackFormatter Instance = new ComplexFormatter(); ComplexFormatter() { } public int Serialize(ref byte[] bytes, int offset, System.Numerics.Complex value, IFormatterResolver formatterResolver) { var startOffset = offset; offset += MessagePackBinary.WriteArrayHeader(ref bytes, offset, 2); offset += MessagePackBinary.WriteDouble(ref bytes, offset, value.Real); offset += MessagePackBinary.WriteDouble(ref bytes, offset, value.Imaginary); return offset - startOffset; } public System.Numerics.Complex Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { var startOffset = offset; var count = MessagePackBinary.ReadArrayHeader(bytes, offset, out readSize); offset += readSize; if (count != 2) throw new InvalidOperationException("Invalid Complex format."); var real = MessagePackBinary.ReadDouble(bytes, offset, out readSize); offset += readSize; var imaginary = MessagePackBinary.ReadDouble(bytes, offset, out readSize); offset += readSize; readSize = offset - startOffset; return new System.Numerics.Complex(real, imaginary); } } public sealed class LazyFormatter : IMessagePackFormatter> { public int Serialize(ref byte[] bytes, int offset, Lazy value, IFormatterResolver formatterResolver) { if (value == null) { return MessagePackBinary.WriteNil(ref bytes, offset); } else { return formatterResolver.GetFormatterWithVerify().Serialize(ref bytes, offset, value.Value, formatterResolver); } } public Lazy Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { if (MessagePackBinary.IsNil(bytes, offset)) { readSize = 1; return null; } else { // deserialize immediately(no delay, because capture byte[] causes memory leak) var v = formatterResolver.GetFormatterWithVerify().Deserialize(bytes, offset, formatterResolver, out readSize); return new Lazy(() => v); } } } public sealed class TaskUnitFormatter : IMessagePackFormatter { public static readonly IMessagePackFormatter Instance = new TaskUnitFormatter(); static readonly Task CompletedTask = Task.FromResult(null); TaskUnitFormatter() { } public int Serialize(ref byte[] bytes, int offset, Task value, IFormatterResolver formatterResolver) { if (value == null) { return MessagePackBinary.WriteNil(ref bytes, offset); } else { value.Wait(); // wait...! return MessagePackBinary.WriteNil(ref bytes, offset); } } public Task Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { if (!MessagePackBinary.IsNil(bytes, offset)) { throw new InvalidOperationException("Invalid input"); } else { readSize = 1; return CompletedTask; } } } public sealed class TaskValueFormatter : IMessagePackFormatter> { public int Serialize(ref byte[] bytes, int offset, Task value, IFormatterResolver formatterResolver) { if (value == null) { return MessagePackBinary.WriteNil(ref bytes, offset); } else { // value.Result -> wait...! return formatterResolver.GetFormatterWithVerify().Serialize(ref bytes, offset, value.Result, formatterResolver); } } public Task Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { if (MessagePackBinary.IsNil(bytes, offset)) { readSize = 1; return null; } else { var v = formatterResolver.GetFormatterWithVerify().Deserialize(bytes, offset, formatterResolver, out readSize); return Task.FromResult(v); } } } public sealed class ValueTaskFormatter : IMessagePackFormatter> { public int Serialize(ref byte[] bytes, int offset, ValueTask value, IFormatterResolver formatterResolver) { return formatterResolver.GetFormatterWithVerify().Serialize(ref bytes, offset, value.Result, formatterResolver); } public ValueTask Deserialize(byte[] bytes, int offset, IFormatterResolver formatterResolver, out int readSize) { var v = formatterResolver.GetFormatterWithVerify().Deserialize(bytes, offset, formatterResolver, out readSize); return new ValueTask(v); } } #endif }