using MessagePack.Internal; using System; using System.IO; namespace MessagePack { /// /// High-Level API of MessagePack for C#. /// public static partial class MessagePackSerializer { static IFormatterResolver defaultResolver; /// /// FormatterResolver that used resolver less overloads. If does not set it, used StandardResolver. /// public static IFormatterResolver DefaultResolver { get { if (defaultResolver == null) { defaultResolver = MessagePack.Resolvers.StandardResolver.Instance; } return defaultResolver; } } /// /// Is resolver decided? /// public static bool IsInitialized { get { return defaultResolver != null; } } /// /// Set default resolver of MessagePackSerializer APIs. /// /// public static void SetDefaultResolver(IFormatterResolver resolver) { defaultResolver = resolver; } /// /// Serialize to binary with default resolver. /// public static byte[] Serialize(T obj) { return Serialize(obj, defaultResolver); } /// /// Serialize to binary with specified resolver. /// public static byte[] Serialize(T obj, IFormatterResolver resolver) { if (resolver == null) resolver = DefaultResolver; var formatter = resolver.GetFormatterWithVerify(); var buffer = InternalMemoryPool.GetBuffer(); var len = formatter.Serialize(ref buffer, 0, obj, resolver); // do not return MemoryPool.Buffer. return MessagePackBinary.FastCloneWithResize(buffer, len); } /// /// Serialize to binary. Get the raw memory pool byte[]. The result can not share across thread and can not hold, so use quickly. /// public static ArraySegment SerializeUnsafe(T obj) { return SerializeUnsafe(obj, defaultResolver); } /// /// Serialize to binary with specified resolver. Get the raw memory pool byte[]. The result can not share across thread and can not hold, so use quickly. /// public static ArraySegment SerializeUnsafe(T obj, IFormatterResolver resolver) { if (resolver == null) resolver = DefaultResolver; var formatter = resolver.GetFormatterWithVerify(); var buffer = InternalMemoryPool.GetBuffer(); var len = formatter.Serialize(ref buffer, 0, obj, resolver); // return raw memory pool, unsafe! return new ArraySegment(buffer, 0, len); } /// /// Serialize to stream. /// public static void Serialize(Stream stream, T obj) { Serialize(stream, obj, defaultResolver); } /// /// Serialize to stream with specified resolver. /// public static void Serialize(Stream stream, T obj, IFormatterResolver resolver) { if (resolver == null) resolver = DefaultResolver; var formatter = resolver.GetFormatterWithVerify(); var buffer = InternalMemoryPool.GetBuffer(); var len = formatter.Serialize(ref buffer, 0, obj, resolver); // do not need resize. stream.Write(buffer, 0, len); } /// /// Reflect of resolver.GetFormatterWithVerify[T].Serialize. /// public static int Serialize(ref byte[] bytes, int offset, T value, IFormatterResolver resolver) { return resolver.GetFormatterWithVerify().Serialize(ref bytes, offset, value, resolver); } #if NETSTANDARD /// /// Serialize to stream(async). /// public static System.Threading.Tasks.Task SerializeAsync(Stream stream, T obj) { return SerializeAsync(stream, obj, defaultResolver); } /// /// Serialize to stream(async) with specified resolver. /// public static async System.Threading.Tasks.Task SerializeAsync(Stream stream, T obj, IFormatterResolver resolver) { if (resolver == null) resolver = DefaultResolver; var formatter = resolver.GetFormatterWithVerify(); var rentBuffer = BufferPool.Default.Rent(); try { var buffer = rentBuffer; var len = formatter.Serialize(ref buffer, 0, obj, resolver); // do not need resize. await stream.WriteAsync(buffer, 0, len).ConfigureAwait(false); } finally { BufferPool.Default.Return(rentBuffer); } } #endif public static T Deserialize(byte[] bytes) { return Deserialize(bytes, defaultResolver); } public static T Deserialize(byte[] bytes, IFormatterResolver resolver) { if (resolver == null) resolver = DefaultResolver; var formatter = resolver.GetFormatterWithVerify(); int readSize; return formatter.Deserialize(bytes, 0, resolver, out readSize); } public static T Deserialize(ArraySegment bytes) { return Deserialize(bytes, defaultResolver); } public static T Deserialize(ArraySegment bytes, IFormatterResolver resolver) { if (resolver == null) resolver = DefaultResolver; var formatter = resolver.GetFormatterWithVerify(); int readSize; return formatter.Deserialize(bytes.Array, bytes.Offset, resolver, out readSize); } public static T Deserialize(Stream stream) { return Deserialize(stream, defaultResolver); } public static T Deserialize(Stream stream, IFormatterResolver resolver) { return Deserialize(stream, resolver, false); } public static T Deserialize(Stream stream, bool readStrict) { return Deserialize(stream, defaultResolver, readStrict); } public static T Deserialize(Stream stream, IFormatterResolver resolver, bool readStrict) { if (resolver == null) resolver = DefaultResolver; var formatter = resolver.GetFormatterWithVerify(); if (!readStrict) { #if NETSTANDARD && !NET45 var ms = stream as MemoryStream; if (ms != null) { // optimize for MemoryStream ArraySegment buffer; if (ms.TryGetBuffer(out buffer)) { int readSize; return formatter.Deserialize(buffer.Array, buffer.Offset, resolver, out readSize); } } #endif // no else. { var buffer = InternalMemoryPool.GetBuffer(); FillFromStream(stream, ref buffer); int readSize; return formatter.Deserialize(buffer, 0, resolver, out readSize); } } else { int _; var bytes = MessagePackBinary.ReadMessageBlockFromStreamUnsafe(stream, false, out _); int readSize; return formatter.Deserialize(bytes, 0, resolver, out readSize); } } /// /// Reflect of resolver.GetFormatterWithVerify[T].Deserialize. /// public static T Deserialize(byte[] bytes, int offset, IFormatterResolver resolver, out int readSize) { return resolver.GetFormatterWithVerify().Deserialize(bytes, offset, resolver, out readSize); } #if NETSTANDARD public static System.Threading.Tasks.Task DeserializeAsync(Stream stream) { return DeserializeAsync(stream, defaultResolver); } // readStrict async read is too slow(many Task garbage) so I don't provide async option. public static async System.Threading.Tasks.Task DeserializeAsync(Stream stream, IFormatterResolver resolver) { var rentBuffer = BufferPool.Default.Rent(); var buf = rentBuffer; try { int length = 0; int read; while ((read = await stream.ReadAsync(buf, length, buf.Length - length).ConfigureAwait(false)) > 0) { length += read; if (length == buf.Length) { MessagePackBinary.FastResize(ref buf, length * 2); } } return Deserialize(buf, resolver); } finally { BufferPool.Default.Return(rentBuffer); } } #endif static int FillFromStream(Stream input, ref byte[] buffer) { int length = 0; int read; while ((read = input.Read(buffer, length, buffer.Length - length)) > 0) { length += read; if (length == buffer.Length) { MessagePackBinary.FastResize(ref buffer, length * 2); } } return length; } } } namespace MessagePack.Internal { internal static class InternalMemoryPool { [ThreadStatic] static byte[] buffer = null; public static byte[] GetBuffer() { if (buffer == null) { buffer = new byte[65536]; } return buffer; } } }