140 lines
4.9 KiB
C#
140 lines
4.9 KiB
C#
using System.Buffers;
|
|
using System.Collections.Concurrent;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
|
|
namespace AyCode.Core.Serializers.Jsons;
|
|
|
|
public static partial class AcJsonSerializer
|
|
{
|
|
private static class SerializationContextPool
|
|
{
|
|
private static readonly ConcurrentQueue<JsonSerializationContext> Pool = new();
|
|
private const int MaxPoolSize = 16;
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static JsonSerializationContext Get(in AcJsonSerializerOptions options)
|
|
{
|
|
if (Pool.TryDequeue(out var context))
|
|
{
|
|
context.Reset(options);
|
|
return context;
|
|
}
|
|
return new JsonSerializationContext(options);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static void Return(JsonSerializationContext context)
|
|
{
|
|
if (Pool.Count < MaxPoolSize)
|
|
{
|
|
context.Clear();
|
|
Pool.Enqueue(context);
|
|
}
|
|
}
|
|
}
|
|
|
|
private sealed class JsonSerializationContext : SerializationContextBase<JsonSerializeTypeMetadata>, IDisposable
|
|
{
|
|
private readonly ArrayBufferWriter<byte> _buffer;
|
|
public Utf8JsonWriter Writer { get; private set; }
|
|
|
|
// Use shared reference tracker from AcSerializerCommon
|
|
private readonly AcSerializerCommon.SerializationReferenceTracker _refTracker = new();
|
|
|
|
private static readonly JsonWriterOptions WriterOptions = new()
|
|
{
|
|
Indented = false,
|
|
SkipValidation = true // Skip validation for performance
|
|
};
|
|
|
|
public JsonSerializationContext(in AcJsonSerializerOptions options)
|
|
{
|
|
_buffer = new ArrayBufferWriter<byte>(4096);
|
|
Writer = new Utf8JsonWriter(_buffer, WriterOptions);
|
|
Reset(options);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Factory for creating JsonSerializeTypeMetadata instances.
|
|
/// </summary>
|
|
protected override Func<Type, JsonSerializeTypeMetadata> MetadataFactory
|
|
=> static t => new JsonSerializeTypeMetadata(t);
|
|
|
|
public override void Reset(in AcSerializerOptions options)
|
|
{
|
|
_refTracker.Reset();
|
|
|
|
if (ReferenceHandling != ReferenceHandlingMode.None)
|
|
{
|
|
_refTracker.EnsureInitialized();
|
|
}
|
|
|
|
base.Reset(options);
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
Writer.Reset();
|
|
_buffer.Clear();
|
|
_refTracker.Reset();
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public bool TrackForScanning(object obj) => _refTracker.TrackForScanning(obj);
|
|
|
|
/// <summary>
|
|
/// IId-aware tracking for reference scanning.
|
|
/// Uses IId.Id for IId types, RuntimeHelpers.GetHashCode for others.
|
|
/// </summary>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public bool TrackForScanningWithIId(object obj, JsonSerializeTypeMetadata metadata)
|
|
{
|
|
int existingRefId;
|
|
return _refTracker.TrackForScanningWithIId(obj, metadata, out existingRefId);
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public bool ShouldWriteId(object obj, out int id) => _refTracker.ShouldWriteId(obj, out id);
|
|
|
|
/// <summary>
|
|
/// IId-aware check for reference ID writing.
|
|
/// </summary>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public bool ShouldWriteIdForIId(object obj, JsonSerializeTypeMetadata metadata, out int id)
|
|
=> _refTracker.ShouldWriteIdForIId(obj, metadata, out id);
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void MarkAsWritten(object obj, int id) => _refTracker.MarkAsWritten(obj, id);
|
|
|
|
/// <summary>
|
|
/// IId-aware mark as written.
|
|
/// </summary>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public void MarkAsWrittenForIId(object obj, JsonSerializeTypeMetadata metadata, int id)
|
|
=> _refTracker.MarkAsWrittenForIId(obj, metadata, id);
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public bool TryGetExistingRef(object obj, out int refId) => _refTracker.TryGetExistingRef(obj, out refId);
|
|
|
|
/// <summary>
|
|
/// IId-aware existing ref lookup.
|
|
/// </summary>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public bool TryGetExistingRefForIId(object obj, JsonSerializeTypeMetadata metadata, out int refId)
|
|
=> _refTracker.TryGetExistingRefForIId(obj, metadata, out refId);
|
|
|
|
public string GetResult()
|
|
{
|
|
Writer.Flush();
|
|
return Encoding.UTF8.GetString(_buffer.WrittenSpan);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Writer.Dispose();
|
|
}
|
|
}
|
|
}
|