mirror of
https://github.com/StarBeat/UnityDependencyAnalyzer.git
synced 2026-03-08 05:35:27 +08:00
160 lines
4.8 KiB
C#
160 lines
4.8 KiB
C#
|
|
using System;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using System.IO;
|
||
|
|
using System.Linq;
|
||
|
|
using System.Net.Http;
|
||
|
|
using System.Threading;
|
||
|
|
using System.Threading.Tasks;
|
||
|
|
|
||
|
|
#nullable enable
|
||
|
|
using MemoryPack.Internal;
|
||
|
|
using System.Buffers;
|
||
|
|
using System.Diagnostics.CodeAnalysis;
|
||
|
|
using System.Runtime.CompilerServices;
|
||
|
|
using System.Runtime.InteropServices;
|
||
|
|
|
||
|
|
namespace MemoryPack {
|
||
|
|
|
||
|
|
public static partial class MemoryPackSerializer
|
||
|
|
{
|
||
|
|
[ThreadStatic]
|
||
|
|
static MemoryPackReaderOptionalState? threadStaticReaderOptionalState;
|
||
|
|
|
||
|
|
public static T? Deserialize<T>(ReadOnlySpan<byte> buffer, MemoryPackSerializerOptions? options = default)
|
||
|
|
{
|
||
|
|
T? value = default;
|
||
|
|
Deserialize(buffer, ref value, options);
|
||
|
|
return value;
|
||
|
|
}
|
||
|
|
|
||
|
|
public static int Deserialize<T>(ReadOnlySpan<byte> buffer, ref T? value, MemoryPackSerializerOptions? options = default)
|
||
|
|
{
|
||
|
|
if (!RuntimeHelpers.IsReferenceOrContainsReferences<T>())
|
||
|
|
{
|
||
|
|
if (buffer.Length < Unsafe.SizeOf<T>())
|
||
|
|
{
|
||
|
|
MemoryPackSerializationException.ThrowInvalidRange(Unsafe.SizeOf<T>(), buffer.Length);
|
||
|
|
}
|
||
|
|
value = Unsafe.ReadUnaligned<T>(ref MemoryMarshal.GetReference(buffer));
|
||
|
|
return Unsafe.SizeOf<T>();
|
||
|
|
}
|
||
|
|
|
||
|
|
var state = threadStaticReaderOptionalState;
|
||
|
|
if (state == null)
|
||
|
|
{
|
||
|
|
state = threadStaticReaderOptionalState = new MemoryPackReaderOptionalState();
|
||
|
|
}
|
||
|
|
state.Init(options);
|
||
|
|
|
||
|
|
var reader = new MemoryPackReader(buffer, state);
|
||
|
|
try
|
||
|
|
{
|
||
|
|
reader.ReadValue(ref value);
|
||
|
|
return reader.Consumed;
|
||
|
|
}
|
||
|
|
finally
|
||
|
|
{
|
||
|
|
reader.Dispose();
|
||
|
|
state.Reset();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public static T? Deserialize<T>(in ReadOnlySequence<byte> buffer, MemoryPackSerializerOptions? options = default)
|
||
|
|
{
|
||
|
|
T? value = default;
|
||
|
|
Deserialize<T>(buffer, ref value, options);
|
||
|
|
return value;
|
||
|
|
}
|
||
|
|
|
||
|
|
public static int Deserialize<T>(in ReadOnlySequence<byte> buffer, ref T? value, MemoryPackSerializerOptions? options = default)
|
||
|
|
{
|
||
|
|
var state = threadStaticReaderOptionalState;
|
||
|
|
if (state == null)
|
||
|
|
{
|
||
|
|
state = threadStaticReaderOptionalState = new MemoryPackReaderOptionalState();
|
||
|
|
}
|
||
|
|
state.Init(options);
|
||
|
|
|
||
|
|
var reader = new MemoryPackReader(buffer, state);
|
||
|
|
try
|
||
|
|
{
|
||
|
|
reader.ReadValue(ref value);
|
||
|
|
return reader.Consumed;
|
||
|
|
}
|
||
|
|
finally
|
||
|
|
{
|
||
|
|
reader.Dispose();
|
||
|
|
state.Reset();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public static async ValueTask<T?> DeserializeAsync<T>(Stream stream, MemoryPackSerializerOptions? options = default, CancellationToken cancellationToken = default)
|
||
|
|
{
|
||
|
|
if (stream is MemoryStream ms && ms.TryGetBuffer(out ArraySegment<byte> streamBuffer))
|
||
|
|
{
|
||
|
|
cancellationToken.ThrowIfCancellationRequested();
|
||
|
|
T? value = default;
|
||
|
|
var bytesRead = Deserialize<T>(streamBuffer.AsSpan(checked((int)ms.Position)), ref value, options);
|
||
|
|
|
||
|
|
// Emulate that we had actually "read" from the stream.
|
||
|
|
ms.Seek(bytesRead, SeekOrigin.Current);
|
||
|
|
|
||
|
|
return value;
|
||
|
|
}
|
||
|
|
|
||
|
|
var builder = ReusableReadOnlySequenceBuilderPool.Rent();
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var buffer = ArrayPool<byte>.Shared.Rent(65536); // initial 64K
|
||
|
|
var offset = 0;
|
||
|
|
do
|
||
|
|
{
|
||
|
|
if (offset == buffer.Length)
|
||
|
|
{
|
||
|
|
builder.Add(buffer, returnToPool: true);
|
||
|
|
buffer = ArrayPool<byte>.Shared.Rent(MathEx.NewArrayCapacity(buffer.Length));
|
||
|
|
offset = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int read = 0;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
read = await stream.ReadAsync(buffer.AsMemory(offset, buffer.Length - offset), cancellationToken).ConfigureAwait(false);
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
// buffer is not added in builder, so return here.
|
||
|
|
ArrayPool<byte>.Shared.Return(buffer);
|
||
|
|
throw;
|
||
|
|
}
|
||
|
|
|
||
|
|
offset += read;
|
||
|
|
|
||
|
|
if (read == 0)
|
||
|
|
{
|
||
|
|
builder.Add(buffer.AsMemory(0, offset), returnToPool: true);
|
||
|
|
break;
|
||
|
|
|
||
|
|
}
|
||
|
|
} while (true);
|
||
|
|
|
||
|
|
// If single buffer, we can avoid ReadOnlySequence build cost.
|
||
|
|
if (builder.TryGetSingleMemory(out var memory))
|
||
|
|
{
|
||
|
|
return Deserialize<T>(memory.Span, options);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
var seq = builder.Build();
|
||
|
|
var result = Deserialize<T>(seq, options);
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
finally
|
||
|
|
{
|
||
|
|
builder.Reset();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|