AyCode.Core/AyCode.Core/Serializers/Jsons/AcJsonSerializer.JsonSerial...

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();
}
}
}