127 lines
4.5 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|
|
}
|