| File: System\Text\Json\Serialization\WriteStackFrame.cs | Web Access |
| Project: src\runtime\src\libraries\System.Text.Json\src\System.Text.Json.csproj (System.Text.Json) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; using System.Diagnostics; using System.Runtime.InteropServices; using System.Text.Json.Serialization; using System.Text.Json.Serialization.Metadata; namespace System.Text.Json { [StructLayout(LayoutKind.Auto)] [DebuggerDisplay("{DebuggerDisplay,nq}")] internal struct WriteStackFrame { /// <summary> /// The enumerator for resumable collections. /// </summary> public IEnumerator? CollectionEnumerator; /// <summary> /// The async enumerator for resumable async enumerable collections. /// </summary> public object? AsyncEnumerator; /// <summary> /// The state of the async enumerator for the current stack frame. /// </summary> public AsyncEnumeratorState AsyncEnumeratorState; /// <summary> /// The original JsonPropertyInfo that is not changed. It contains all properties. /// </summary> /// <remarks> /// For objects, it is either the actual (real) JsonPropertyInfo or the <see cref="JsonTypeInfo.PropertyInfoForTypeInfo"/> for the class. /// For collections, it is the <see cref="JsonTypeInfo.PropertyInfoForTypeInfo"/> for the class and current element. /// </remarks> public JsonPropertyInfo? JsonPropertyInfo; /// <summary> /// Used when processing extension data dictionaries. /// </summary> public bool IsWritingExtensionDataProperty; /// <summary> /// The class (POCO or IEnumerable) that is being populated. /// </summary> public JsonTypeInfo JsonTypeInfo; /// <summary> /// Validation state for a class. /// </summary> public int OriginalDepth; // Class-level state for collections. public bool ProcessedStartToken; public bool ProcessedEndToken; /// <summary> /// Property or Element state. /// </summary> public StackFramePropertyState PropertyState; /// <summary> /// The enumerator index for resumable collections. /// </summary> public int EnumeratorIndex; // This is used for re-entry cases for exception handling. public string? JsonPropertyNameAsString; // Preserve Reference public MetadataPropertyName MetadataPropertyName; // Serialization state for the child value serialized by the current frame. public PolymorphicSerializationState PolymorphicSerializationState; // Holds the entered polymorphic type info and acts as an LRU cache for element/field serializations. public JsonTypeInfo? PolymorphicTypeInfo; // Whether to use custom number handling. public JsonNumberHandling? NumberHandling; public bool IsPushedReferenceForCycleDetection; public void EndCollectionElement() { PolymorphicSerializationState = PolymorphicSerializationState.None; } public void EndDictionaryEntry() { PropertyState = StackFramePropertyState.None; PolymorphicSerializationState = PolymorphicSerializationState.None; } public void EndProperty() { JsonPropertyInfo = null!; JsonPropertyNameAsString = null; PropertyState = StackFramePropertyState.None; PolymorphicSerializationState = PolymorphicSerializationState.None; } /// <summary> /// Returns the JsonTypeInfo instance for the nested value we are trying to access. /// </summary> public readonly JsonTypeInfo GetNestedJsonTypeInfo() { return PolymorphicSerializationState is PolymorphicSerializationState.PolymorphicReEntryStarted ? PolymorphicTypeInfo! : JsonPropertyInfo!.JsonTypeInfo; } /// <summary> /// Configures the next stack frame for a polymorphic converter. /// </summary> public JsonTypeInfo InitializePolymorphicReEntry(Type runtimeType, JsonSerializerOptions options) { Debug.Assert(PolymorphicSerializationState == PolymorphicSerializationState.None); // For perf, avoid the dictionary lookup in GetTypeInfoInternal() for every element of a collection // if the current element is the same type as the previous element. if (PolymorphicTypeInfo?.Type != runtimeType) { // To determine the contract for an object value: // 1. Find the JsonTypeInfo for the runtime type with fallback to the nearest ancestor, if not available. // 2. If the resolved type is deriving from a polymorphic type, use the contract of the polymorphic type instead. JsonTypeInfo typeInfo = options.GetTypeInfoInternal(runtimeType, fallBackToNearestAncestorType: true); PolymorphicTypeInfo = typeInfo.AncestorPolymorphicType ?? typeInfo; } PolymorphicSerializationState = PolymorphicSerializationState.PolymorphicReEntryStarted; return PolymorphicTypeInfo; } /// <summary> /// Configures the next stack frame for a polymorphic converter. /// </summary> public JsonConverter InitializePolymorphicReEntry(JsonTypeInfo derivedJsonTypeInfo) { Debug.Assert(PolymorphicSerializationState is PolymorphicSerializationState.None or PolymorphicSerializationState.PolymorphicReEntryStarted); PolymorphicTypeInfo = derivedJsonTypeInfo; PolymorphicSerializationState = PolymorphicSerializationState.PolymorphicReEntryStarted; return derivedJsonTypeInfo.Converter; } /// <summary> /// Configures the next frame for a continuation of a polymorphic converter. /// </summary> public JsonConverter ResumePolymorphicReEntry() { Debug.Assert(PolymorphicSerializationState == PolymorphicSerializationState.PolymorphicReEntrySuspended); Debug.Assert(PolymorphicTypeInfo is not null); PolymorphicSerializationState = PolymorphicSerializationState.PolymorphicReEntryStarted; return PolymorphicTypeInfo.Converter; } /// <summary> /// Updates frame state after a polymorphic converter has returned. /// </summary> public void ExitPolymorphicConverter(bool success) { PolymorphicSerializationState = success ? PolymorphicSerializationState.None : PolymorphicSerializationState.PolymorphicReEntrySuspended; } [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly string DebuggerDisplay => $"ConverterStrategy.{JsonTypeInfo?.Converter.ConverterStrategy}, {JsonTypeInfo?.Type.Name}"; } }