AyCode.Core/AyCode.Core/Serializers/Jsons/AcJsonDeserializer.JsonDese...

127 lines
4.5 KiB
C#

using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
namespace AyCode.Core.Serializers.Jsons;
public static partial class AcJsonDeserializer
{
private static class JsonDeserializationContextPool
{
private static readonly ConcurrentQueue<DeserializationContext> Pool = new();
[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, in AcJsonSerializerOptions options)
{
if (Pool.Count < options.MaxContextPoolSize)
{
context.Clear(options);
Pool.Enqueue(context);
}
}
}
private sealed class DeferredReference(int refId, Type targetType)
{
public int RefId { get; } = refId;
public Type TargetType { get; } = targetType;
}
private readonly struct PropertyToResolve(object target, PropertySetterInfo property, int refId)
{
public readonly object Target = target;
public readonly PropertySetterInfo Property = property;
public readonly int RefId = refId;
}
private sealed class DeserializationContext : AcSerializerContextBase<JsonDeserializeTypeMetadata, AcJsonSerializerOptions>
{
// Use shared reference tracker from AcSerializerCommon
private readonly AcSerializerCommon.DeserializationReferenceTracker _refTracker = new();
private List<PropertyToResolve>? _propertiesToResolve;
public bool IsMergeMode { get; 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;
/// <summary>
/// Factory for creating JsonDeserializeTypeMetadata instances.
/// </summary>
protected override MetadataFactoryDelegate MetadataFactory
=> static ([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(TypeMetadataBase.RequiredMembers)] t)
=> new JsonDeserializeTypeMetadata(t);
public DeserializationContext(in AcJsonSerializerOptions options)
{
Reset(options);
}
public override void Reset(AcJsonSerializerOptions options)
{
// IMPORTANT: base.Reset sets Options first
base.Reset(options);
IsMergeMode = false;
ChainTracker = null;
_refTracker.Reset();
}
public void Clear(AcJsonSerializerOptions options)
{
_refTracker.Reset();
_propertiesToResolve?.Clear();
ChainTracker = null;
Reset(options);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RegisterObject(int id, object obj)
{
if (ReferenceHandling == ReferenceHandlingMode.None) return;
_refTracker.RegisterObject(id, obj);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryGetReferencedObject(int id, out object? obj)
=> _refTracker.TryGetReferencedObject(id, out obj);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddPropertyToResolve(object target, PropertySetterInfo property, int refId)
{
_propertiesToResolve ??= new List<PropertyToResolve>(4);
_propertiesToResolve.Add(new PropertyToResolve(target, property, refId));
}
public void ResolveReferences()
{
if (_propertiesToResolve == null) return;
foreach (ref readonly var ptr in System.Runtime.InteropServices.CollectionsMarshal.AsSpan(_propertiesToResolve))
{
if (_refTracker.TryGetReferencedObject(ptr.RefId, out var refObj))
ptr.Property.SetValue(ptr.Target, refObj);
}
}
}
}