WriteStack
struct WriteStack
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Pipelines;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using System.Threading;
using System.Threading.Tasks;
namespace System.Text.Json
{
[StructLayout(LayoutKind.Auto)]
[DebuggerDisplay("{DebuggerDisplay,nq}")]
internal struct WriteStack
{
public WriteStackFrame Current;
private WriteStackFrame[] _stack;
private int _count;
private int _continuationCount;
private byte _indexOffset;
public CancellationToken CancellationToken;
public bool SuppressFlush;
public Task PendingTask;
public List<IAsyncDisposable> CompletedAsyncDisposables;
public int FlushThreshold;
public PipeWriter PipeWriter;
public ReferenceResolver ReferenceResolver;
public bool SupportContinuation;
public bool SupportAsync;
public string NewReferenceId;
public object PolymorphicTypeDiscriminator;
public PolymorphicTypeResolver PolymorphicTypeResolver;
public int CurrentDepth {
[System.Runtime.CompilerServices.IsReadOnly]
get {
return _count;
}
}
public ref WriteStackFrame Parent {
[System.Runtime.CompilerServices.IsReadOnly]
get {
return ref _stack[_count - _indexOffset - 1];
}
}
public bool IsContinuation {
[System.Runtime.CompilerServices.IsReadOnly]
get {
return _continuationCount != 0;
}
}
public bool CurrentContainsMetadata {
[System.Runtime.CompilerServices.IsReadOnly]
get {
if (NewReferenceId == null)
return PolymorphicTypeDiscriminator != null;
return true;
}
}
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string DebuggerDisplay {
get {
return $"""{PropertyPath()}""{Current.JsonPropertyInfo?.EffectiveConverter.ConverterStrategy}""{Current.JsonTypeInfo?.Type.Name}";
}
}
private void EnsurePushCapacity()
{
if (_stack == null)
_stack = new WriteStackFrame[4];
else if (_count - _indexOffset == _stack.Length) {
Array.Resize(ref _stack, 2 * _stack.Length);
}
}
internal void Initialize(JsonTypeInfo jsonTypeInfo, object rootValueBoxed = null, bool supportContinuation = false, bool supportAsync = false)
{
Current.JsonTypeInfo = jsonTypeInfo;
Current.JsonPropertyInfo = jsonTypeInfo.PropertyInfoForTypeInfo;
Current.NumberHandling = Current.JsonPropertyInfo.EffectiveNumberHandling;
SupportContinuation = supportContinuation;
SupportAsync = supportAsync;
JsonSerializerOptions options = jsonTypeInfo.Options;
if (options.ReferenceHandlingStrategy != 0) {
ReferenceResolver = options.ReferenceHandler.CreateResolver(true);
if (options.ReferenceHandlingStrategy == ReferenceHandlingStrategy.IgnoreCycles && rootValueBoxed != null && jsonTypeInfo.Type.IsValueType)
ReferenceResolver.PushReferenceForCycleDetection(rootValueBoxed);
}
}
[System.Runtime.CompilerServices.IsReadOnly]
public JsonTypeInfo PeekNestedJsonTypeInfo()
{
if (_count != 0)
return Current.JsonPropertyInfo.JsonTypeInfo;
return Current.JsonTypeInfo;
}
public void Push()
{
if (_continuationCount == 0) {
if (_count == 0 && Current.PolymorphicSerializationState == PolymorphicSerializationState.None) {
_count = 1;
_indexOffset = 1;
} else {
JsonTypeInfo nestedJsonTypeInfo = Current.GetNestedJsonTypeInfo();
JsonNumberHandling? numberHandling = Current.NumberHandling;
EnsurePushCapacity();
_stack[_count - _indexOffset] = Current;
Current = default(WriteStackFrame);
_count++;
Current.JsonTypeInfo = nestedJsonTypeInfo;
Current.JsonPropertyInfo = nestedJsonTypeInfo.PropertyInfoForTypeInfo;
Current.NumberHandling = (numberHandling ?? Current.JsonPropertyInfo.EffectiveNumberHandling);
}
} else {
if (_count++ > 0 || _indexOffset == 0)
Current = _stack[_count - _indexOffset];
if (_continuationCount == _count)
_continuationCount = 0;
}
}
public void Pop(bool success)
{
if (!success) {
if (_continuationCount == 0) {
if (_count == 1 && _indexOffset > 0) {
_continuationCount = 1;
_count = 0;
return;
}
EnsurePushCapacity();
_continuationCount = _count--;
} else if (--_count == 0 && _indexOffset > 0) {
return;
}
int num = _count - _indexOffset;
_stack[num + 1] = Current;
Current = _stack[num];
} else if (--_count > 0 || _indexOffset == 0) {
Current = _stack[_count - _indexOffset];
}
}
public void AddCompletedAsyncDisposable(IAsyncDisposable asyncDisposable)
{
(CompletedAsyncDisposables ?? (CompletedAsyncDisposables = new List<IAsyncDisposable>())).Add(asyncDisposable);
}
[System.Runtime.CompilerServices.IsReadOnly]
[AsyncStateMachine(typeof(<DisposeCompletedAsyncDisposables>d__31))]
public ValueTask DisposeCompletedAsyncDisposables()
{
<DisposeCompletedAsyncDisposables>d__31 stateMachine = default(<DisposeCompletedAsyncDisposables>d__31);
stateMachine.<>t__builder = AsyncValueTaskMethodBuilder.Create();
stateMachine.<>4__this = this;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
[System.Runtime.CompilerServices.IsReadOnly]
public void DisposePendingDisposablesOnException()
{
Exception exception = null;
<DisposePendingDisposablesOnException>g__DisposeFrame|32_0(Current.CollectionEnumerator, ref exception);
int num = Math.Max(_count, _continuationCount);
for (int i = 0; i < num - 1; i++) {
<DisposePendingDisposablesOnException>g__DisposeFrame|32_0(_stack[i].CollectionEnumerator, ref exception);
}
if (exception != null)
ExceptionDispatchInfo.Capture(exception).Throw();
}
[System.Runtime.CompilerServices.IsReadOnly]
[AsyncStateMachine(typeof(<DisposePendingDisposablesOnExceptionAsync>d__33))]
public ValueTask DisposePendingDisposablesOnExceptionAsync()
{
<DisposePendingDisposablesOnExceptionAsync>d__33 stateMachine = default(<DisposePendingDisposablesOnExceptionAsync>d__33);
stateMachine.<>t__builder = AsyncValueTaskMethodBuilder.Create();
stateMachine.<>4__this = this;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
public string PropertyPath()
{
StringBuilder stringBuilder = new StringBuilder("$");
int continuationCount = _continuationCount;
(int, bool) valueTuple;
switch (continuationCount) {
case 0:
valueTuple = (_count - 1, true);
break;
case 1:
valueTuple = (0, true);
break;
default:
valueTuple = (continuationCount, false);
break;
}
(int, bool) valueTuple2 = valueTuple;
int item = valueTuple2.Item1;
bool item2 = valueTuple2.Item2;
for (int i = 1; i <= item; i++) {
<PropertyPath>g__AppendStackFrame|34_0(stringBuilder, ref _stack[i - _indexOffset]);
}
if (item2)
<PropertyPath>g__AppendStackFrame|34_0(stringBuilder, ref Current);
return stringBuilder.ToString();
}
}
}