AyCode.Core/AyCode.Core/Serializers/Jsons/AcJsonDeserializer.Deserial...

123 lines
4.1 KiB
C#

using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
namespace AyCode.Core.Serializers.Jsons;
public static partial class AcJsonDeserializer
{
private static class DeserializationContextPool
{
private static readonly ConcurrentQueue<DeserializationContext> Pool = new();
private const int MaxPoolSize = 16;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static DeserializationContext Get(in AcJsonSerializerOptions options)
{
if (Pool.TryDequeue(out var context))
{
context.Reset(options);
return context;
}
return new DeserializationContext(options);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Return(DeserializationContext context)
{
if (Pool.Count < MaxPoolSize)
{
context.Clear();
Pool.Enqueue(context);
}
}
}
private sealed class DeferredReference(string refId, Type targetType)
{
public string RefId { get; } = refId;
public Type TargetType { get; } = targetType;
}
private readonly struct PropertyToResolve(object target, PropertySetterInfo property, string refId)
{
public readonly object Target = target;
public readonly PropertySetterInfo Property = property;
public readonly string RefId = refId;
}
private sealed class DeserializationContext
{
private Dictionary<string, object>? _idToObject;
private List<PropertyToResolve>? _propertiesToResolve;
public bool IsMergeMode { get; set; }
public bool UseReferenceHandling { get; private set; }
public byte MaxDepth { get; private set; }
/// <summary>
/// Chain reference tracker for maintaining object identity across chain operations.
/// Only set when in chain mode (CreateDeserializeChain).
/// </summary>
public AcSerializerCommon.ChainReferenceTracker? ChainTracker { get; set; }
/// <summary>
/// Returns true if in chain mode (ChainTracker is set).
/// </summary>
public bool IsChainMode => ChainTracker != null;
public DeserializationContext(in AcJsonSerializerOptions options)
{
Reset(options);
}
public void Reset(in AcJsonSerializerOptions options)
{
UseReferenceHandling = options.UseReferenceHandling;
MaxDepth = options.MaxDepth;
IsMergeMode = false;
ChainTracker = null;
}
public void Clear()
{
_idToObject?.Clear();
_propertiesToResolve?.Clear();
ChainTracker = null;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RegisterObject(string id, object obj)
{
if (!UseReferenceHandling) return;
_idToObject ??= new Dictionary<string, object>(8, StringComparer.Ordinal);
_idToObject[id] = obj;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryGetReferencedObject(string id, out object? obj)
{
if (_idToObject != null) return _idToObject.TryGetValue(id, out obj);
obj = null;
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddPropertyToResolve(object target, PropertySetterInfo property, string refId)
{
_propertiesToResolve ??= new List<PropertyToResolve>(4);
_propertiesToResolve.Add(new PropertyToResolve(target, property, refId));
}
public void ResolveReferences()
{
if (_propertiesToResolve == null || _idToObject == null) return;
foreach (ref readonly var ptr in System.Runtime.InteropServices.CollectionsMarshal.AsSpan(_propertiesToResolve))
{
if (_idToObject.TryGetValue(ptr.RefId, out var refObj))
ptr.Property.SetValue(ptr.Target, refObj);
}
}
}
}