You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
327 lines
10 KiB
327 lines
10 KiB
4 years ago
|
using MessagePack.Internal;
|
||
|
using System;
|
||
|
using System.IO;
|
||
|
|
||
|
namespace MessagePack
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// High-Level API of MessagePack for C#.
|
||
|
/// </summary>
|
||
|
public static partial class MessagePackSerializer
|
||
|
{
|
||
|
static IFormatterResolver defaultResolver;
|
||
|
|
||
|
/// <summary>
|
||
|
/// FormatterResolver that used resolver less overloads. If does not set it, used StandardResolver.
|
||
|
/// </summary>
|
||
|
public static IFormatterResolver DefaultResolver
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (defaultResolver == null)
|
||
|
{
|
||
|
defaultResolver = MessagePack.Resolvers.StandardResolver.Instance;
|
||
|
}
|
||
|
|
||
|
return defaultResolver;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Is resolver decided?
|
||
|
/// </summary>
|
||
|
public static bool IsInitialized
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return defaultResolver != null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Set default resolver of MessagePackSerializer APIs.
|
||
|
/// </summary>
|
||
|
/// <param name="resolver"></param>
|
||
|
public static void SetDefaultResolver(IFormatterResolver resolver)
|
||
|
{
|
||
|
defaultResolver = resolver;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Serialize to binary with default resolver.
|
||
|
/// </summary>
|
||
|
public static byte[] Serialize<T>(T obj)
|
||
|
{
|
||
|
return Serialize(obj, defaultResolver);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Serialize to binary with specified resolver.
|
||
|
/// </summary>
|
||
|
public static byte[] Serialize<T>(T obj, IFormatterResolver resolver)
|
||
|
{
|
||
|
if (resolver == null) resolver = DefaultResolver;
|
||
|
var formatter = resolver.GetFormatterWithVerify<T>();
|
||
|
|
||
|
var buffer = InternalMemoryPool.GetBuffer();
|
||
|
|
||
|
var len = formatter.Serialize(ref buffer, 0, obj, resolver);
|
||
|
|
||
|
// do not return MemoryPool.Buffer.
|
||
|
return MessagePackBinary.FastCloneWithResize(buffer, len);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Serialize to binary. Get the raw memory pool byte[]. The result can not share across thread and can not hold, so use quickly.
|
||
|
/// </summary>
|
||
|
public static ArraySegment<byte> SerializeUnsafe<T>(T obj)
|
||
|
{
|
||
|
return SerializeUnsafe(obj, defaultResolver);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 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.
|
||
|
/// </summary>
|
||
|
public static ArraySegment<byte> SerializeUnsafe<T>(T obj, IFormatterResolver resolver)
|
||
|
{
|
||
|
if (resolver == null) resolver = DefaultResolver;
|
||
|
var formatter = resolver.GetFormatterWithVerify<T>();
|
||
|
|
||
|
var buffer = InternalMemoryPool.GetBuffer();
|
||
|
|
||
|
var len = formatter.Serialize(ref buffer, 0, obj, resolver);
|
||
|
|
||
|
// return raw memory pool, unsafe!
|
||
|
return new ArraySegment<byte>(buffer, 0, len);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Serialize to stream.
|
||
|
/// </summary>
|
||
|
public static void Serialize<T>(Stream stream, T obj)
|
||
|
{
|
||
|
Serialize(stream, obj, defaultResolver);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Serialize to stream with specified resolver.
|
||
|
/// </summary>
|
||
|
public static void Serialize<T>(Stream stream, T obj, IFormatterResolver resolver)
|
||
|
{
|
||
|
if (resolver == null) resolver = DefaultResolver;
|
||
|
var formatter = resolver.GetFormatterWithVerify<T>();
|
||
|
|
||
|
var buffer = InternalMemoryPool.GetBuffer();
|
||
|
|
||
|
var len = formatter.Serialize(ref buffer, 0, obj, resolver);
|
||
|
|
||
|
// do not need resize.
|
||
|
stream.Write(buffer, 0, len);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reflect of resolver.GetFormatterWithVerify[T].Serialize.
|
||
|
/// </summary>
|
||
|
public static int Serialize<T>(ref byte[] bytes, int offset, T value, IFormatterResolver resolver)
|
||
|
{
|
||
|
return resolver.GetFormatterWithVerify<T>().Serialize(ref bytes, offset, value, resolver);
|
||
|
}
|
||
|
|
||
|
#if NETSTANDARD
|
||
|
|
||
|
/// <summary>
|
||
|
/// Serialize to stream(async).
|
||
|
/// </summary>
|
||
|
public static System.Threading.Tasks.Task SerializeAsync<T>(Stream stream, T obj)
|
||
|
{
|
||
|
return SerializeAsync(stream, obj, defaultResolver);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Serialize to stream(async) with specified resolver.
|
||
|
/// </summary>
|
||
|
public static async System.Threading.Tasks.Task SerializeAsync<T>(Stream stream, T obj, IFormatterResolver resolver)
|
||
|
{
|
||
|
if (resolver == null) resolver = DefaultResolver;
|
||
|
var formatter = resolver.GetFormatterWithVerify<T>();
|
||
|
|
||
|
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<T>(byte[] bytes)
|
||
|
{
|
||
|
return Deserialize<T>(bytes, defaultResolver);
|
||
|
}
|
||
|
|
||
|
public static T Deserialize<T>(byte[] bytes, IFormatterResolver resolver)
|
||
|
{
|
||
|
if (resolver == null) resolver = DefaultResolver;
|
||
|
var formatter = resolver.GetFormatterWithVerify<T>();
|
||
|
|
||
|
int readSize;
|
||
|
return formatter.Deserialize(bytes, 0, resolver, out readSize);
|
||
|
}
|
||
|
|
||
|
public static T Deserialize<T>(ArraySegment<byte> bytes)
|
||
|
{
|
||
|
return Deserialize<T>(bytes, defaultResolver);
|
||
|
}
|
||
|
|
||
|
public static T Deserialize<T>(ArraySegment<byte> bytes, IFormatterResolver resolver)
|
||
|
{
|
||
|
if (resolver == null) resolver = DefaultResolver;
|
||
|
var formatter = resolver.GetFormatterWithVerify<T>();
|
||
|
|
||
|
int readSize;
|
||
|
return formatter.Deserialize(bytes.Array, bytes.Offset, resolver, out readSize);
|
||
|
}
|
||
|
|
||
|
public static T Deserialize<T>(Stream stream)
|
||
|
{
|
||
|
return Deserialize<T>(stream, defaultResolver);
|
||
|
}
|
||
|
|
||
|
public static T Deserialize<T>(Stream stream, IFormatterResolver resolver)
|
||
|
{
|
||
|
return Deserialize<T>(stream, resolver, false);
|
||
|
}
|
||
|
|
||
|
public static T Deserialize<T>(Stream stream, bool readStrict)
|
||
|
{
|
||
|
return Deserialize<T>(stream, defaultResolver, readStrict);
|
||
|
}
|
||
|
|
||
|
public static T Deserialize<T>(Stream stream, IFormatterResolver resolver, bool readStrict)
|
||
|
{
|
||
|
if (resolver == null) resolver = DefaultResolver;
|
||
|
var formatter = resolver.GetFormatterWithVerify<T>();
|
||
|
|
||
|
if (!readStrict)
|
||
|
{
|
||
|
#if NETSTANDARD && !NET45
|
||
|
|
||
|
var ms = stream as MemoryStream;
|
||
|
if (ms != null)
|
||
|
{
|
||
|
// optimize for MemoryStream
|
||
|
ArraySegment<byte> 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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reflect of resolver.GetFormatterWithVerify[T].Deserialize.
|
||
|
/// </summary>
|
||
|
public static T Deserialize<T>(byte[] bytes, int offset, IFormatterResolver resolver, out int readSize)
|
||
|
{
|
||
|
return resolver.GetFormatterWithVerify<T>().Deserialize(bytes, offset, resolver, out readSize);
|
||
|
}
|
||
|
|
||
|
#if NETSTANDARD
|
||
|
|
||
|
public static System.Threading.Tasks.Task<T> DeserializeAsync<T>(Stream stream)
|
||
|
{
|
||
|
return DeserializeAsync<T>(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<T> DeserializeAsync<T>(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<T>(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;
|
||
|
}
|
||
|
}
|
||
|
}
|