123 lines
4.1 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|
|
}
|