using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using Utf8Json.Formatters.Internal; using Utf8Json.Internal; #if NETSTANDARD using System.Collections.Concurrent; #endif namespace Utf8Json.Formatters { public class ArrayFormatter : IJsonFormatter, IOverwriteJsonFormatter { static readonly ArrayPool arrayPool = new ArrayPool(99); readonly CollectionDeserializeToBehaviour deserializeToBehaviour; public ArrayFormatter() : this(CollectionDeserializeToBehaviour.Add) { } public ArrayFormatter(CollectionDeserializeToBehaviour deserializeToBehaviour) { this.deserializeToBehaviour = deserializeToBehaviour; } public void Serialize(ref JsonWriter writer, T[] value, IJsonFormatterResolver formatterResolver) { if (value == null) { writer.WriteNull(); return; } writer.WriteBeginArray(); var formatter = formatterResolver.GetFormatterWithVerify(); if (value.Length != 0) { formatter.Serialize(ref writer, value[0], formatterResolver); } for (int i = 1; i < value.Length; i++) { writer.WriteValueSeparator(); formatter.Serialize(ref writer, value[i], formatterResolver); } writer.WriteEndArray(); } public T[] Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) { if (reader.ReadIsNull()) return null; var count = 0; var formatter = formatterResolver.GetFormatterWithVerify(); var workingArea = arrayPool.Rent(); try { var array = workingArea; reader.ReadIsBeginArrayWithVerify(); while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) { if (array.Length < count) { Array.Resize(ref array, array.Length * 2); } array[count - 1] = formatter.Deserialize(ref reader, formatterResolver); } var result = new T[count]; Array.Copy(array, result, count); Array.Clear(workingArea, 0, Math.Min(count, workingArea.Length)); return result; } finally { arrayPool.Return(workingArea); } } public void DeserializeTo(ref T[] value, ref JsonReader reader, IJsonFormatterResolver formatterResolver) { if (reader.ReadIsNull()) { // null, do nothing(same as empty) return; } var count = 0; var formatter = formatterResolver.GetFormatterWithVerify(); if (deserializeToBehaviour == CollectionDeserializeToBehaviour.Add) { var workingArea = arrayPool.Rent(); try { var array = workingArea; reader.ReadIsBeginArrayWithVerify(); while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) { if (array.Length < count) { Array.Resize(ref array, array.Length * 2); } array[count - 1] = formatter.Deserialize(ref reader, formatterResolver); } if (count == 0) { return; } var result = new T[value.Length + count]; Array.Copy(value, 0, result, 0, value.Length); Array.Copy(array, 0, result, value.Length, count); Array.Clear(workingArea, 0, Math.Min(count, workingArea.Length)); } finally { arrayPool.Return(workingArea); } } else { var array = value; // use same array overwrite set. reader.ReadIsBeginArrayWithVerify(); while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) { if (array.Length < count) { Array.Resize(ref array, array.Length * 2); } array[count - 1] = formatter.Deserialize(ref reader, formatterResolver); } Array.Resize(ref array, count); // resize, fit length. } } } public class ArraySegmentFormatter : IJsonFormatter> { static readonly ArrayPool arrayPool = new ArrayPool(99); public void Serialize(ref JsonWriter writer, ArraySegment value, IJsonFormatterResolver formatterResolver) { if (value.Array == null) { writer.WriteNull(); return; } var array = value.Array; var offset = value.Offset; var count = value.Count; writer.WriteBeginArray(); var formatter = formatterResolver.GetFormatterWithVerify(); if (count != 0) { formatter.Serialize(ref writer, value.Array[offset], formatterResolver); } for (int i = 1; i < count; i++) { writer.WriteValueSeparator(); formatter.Serialize(ref writer, array[offset + i], formatterResolver); } writer.WriteEndArray(); } public ArraySegment Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) { if (reader.ReadIsNull()) return default(ArraySegment); var count = 0; var formatter = formatterResolver.GetFormatterWithVerify(); var workingArea = arrayPool.Rent(); try { var array = workingArea; reader.ReadIsBeginArrayWithVerify(); while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) { if (array.Length < count) { Array.Resize(ref array, array.Length * 2); } array[count - 1] = formatter.Deserialize(ref reader, formatterResolver); } var result = new T[count]; Array.Copy(array, result, count); Array.Clear(workingArea, 0, Math.Min(count, workingArea.Length)); return new ArraySegment(result, 0, result.Length); } finally { arrayPool.Return(workingArea); } } } public class ListFormatter : IJsonFormatter>, IOverwriteJsonFormatter> { readonly CollectionDeserializeToBehaviour deserializeToBehaviour; public ListFormatter() : this(CollectionDeserializeToBehaviour.Add) { } public ListFormatter(CollectionDeserializeToBehaviour deserializeToBehaviour) { this.deserializeToBehaviour = deserializeToBehaviour; } public void Serialize(ref JsonWriter writer, List value, IJsonFormatterResolver formatterResolver) { if (value == null) { writer.WriteNull(); return; } writer.WriteBeginArray(); var formatter = formatterResolver.GetFormatterWithVerify(); if (value.Count != 0) { formatter.Serialize(ref writer, value[0], formatterResolver); } for (int i = 1; i < value.Count; i++) { writer.WriteValueSeparator(); formatter.Serialize(ref writer, value[i], formatterResolver); } writer.WriteEndArray(); } public List Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) { if (reader.ReadIsNull()) return null; var count = 0; var formatter = formatterResolver.GetFormatterWithVerify(); var list = new List(); reader.ReadIsBeginArrayWithVerify(); while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) { list.Add(formatter.Deserialize(ref reader, formatterResolver)); } return list; } public void DeserializeTo(ref List value, ref JsonReader reader, IJsonFormatterResolver formatterResolver) { if (reader.ReadIsNull()) { // null, do nothing return; } var count = 0; var formatter = formatterResolver.GetFormatterWithVerify(); var list = value; // use the reference if (deserializeToBehaviour == CollectionDeserializeToBehaviour.OverwriteReplace) { list.Clear(); // clear before add. } reader.ReadIsBeginArrayWithVerify(); while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) { list.Add(formatter.Deserialize(ref reader, formatterResolver)); } } } public abstract class CollectionFormatterBase : IJsonFormatter, IOverwriteJsonFormatter where TCollection : class, IEnumerable where TEnumerator : IEnumerator { public void Serialize(ref JsonWriter writer, TCollection value, IJsonFormatterResolver formatterResolver) { if (value == null) { writer.WriteNull(); } else { writer.WriteBeginArray(); var formatter = formatterResolver.GetFormatterWithVerify(); // Unity's foreach struct enumerator causes boxing so iterate manually. var e = GetSourceEnumerator(value); try { var isFirst = true; while (e.MoveNext()) { if (isFirst) { isFirst = false; } else { writer.WriteValueSeparator(); } formatter.Serialize(ref writer, e.Current, formatterResolver); } } finally { e.Dispose(); } writer.WriteEndArray(); } } public TCollection Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) { if (reader.ReadIsNull()) { return null; } else { var formatter = formatterResolver.GetFormatterWithVerify(); var builder = Create(); var count = 0; reader.ReadIsBeginArrayWithVerify(); while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) { Add(ref builder, count - 1, formatter.Deserialize(ref reader, formatterResolver)); } return Complete(ref builder); } } public void DeserializeTo(ref TCollection value, ref JsonReader reader, IJsonFormatterResolver formatterResolver) { // not supported if (SupportedOverwriteBehaviour == null) { value = Deserialize(ref reader, formatterResolver); return; } if (reader.ReadIsNull()) return; // do nothing var formatter = formatterResolver.GetFormatterWithVerify(); ClearOnOverwriteDeserialize(ref value); var count = 0; reader.ReadIsBeginArrayWithVerify(); while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) { AddOnOverwriteDeserialize(ref value, count - 1, formatter.Deserialize(ref reader, formatterResolver)); } } // Some collections can use struct iterator, this is optimization path protected abstract TEnumerator GetSourceEnumerator(TCollection source); // abstraction for deserialize protected abstract TIntermediate Create(); protected abstract void Add(ref TIntermediate collection, int index, TElement value); protected abstract TCollection Complete(ref TIntermediate intermediateCollection); // additional support for overwrite protected virtual CollectionDeserializeToBehaviour? SupportedOverwriteBehaviour { get { return null; } } protected virtual void ClearOnOverwriteDeserialize(ref TCollection value) { } protected virtual void AddOnOverwriteDeserialize(ref TCollection collection, int index, TElement value) { } } public abstract class CollectionFormatterBase : CollectionFormatterBase, TCollection> where TCollection : class, IEnumerable { protected override IEnumerator GetSourceEnumerator(TCollection source) { return source.GetEnumerator(); } } public abstract class CollectionFormatterBase : CollectionFormatterBase where TCollection : class, IEnumerable { protected sealed override TCollection Complete(ref TCollection intermediateCollection) { return intermediateCollection; } } public sealed class GenericCollectionFormatter : CollectionFormatterBase where TCollection : class, ICollection, new() { protected override TCollection Create() { return new TCollection(); } protected override void Add(ref TCollection collection, int index, TElement value) { collection.Add(value); } } public sealed class LinkedListFormatter : CollectionFormatterBase, LinkedList.Enumerator, LinkedList> { readonly CollectionDeserializeToBehaviour deserializeToBehaviour; public LinkedListFormatter() : this(CollectionDeserializeToBehaviour.Add) { } public LinkedListFormatter(CollectionDeserializeToBehaviour deserializeToBehaviour) { this.deserializeToBehaviour = deserializeToBehaviour; } protected override void Add(ref LinkedList collection, int index, T value) { collection.AddLast(value); } protected override LinkedList Complete(ref LinkedList intermediateCollection) { return intermediateCollection; } protected override LinkedList Create() { return new LinkedList(); } protected override LinkedList.Enumerator GetSourceEnumerator(LinkedList source) { return source.GetEnumerator(); } protected override CollectionDeserializeToBehaviour? SupportedOverwriteBehaviour { get { return deserializeToBehaviour; } } protected override void AddOnOverwriteDeserialize(ref LinkedList collection, int index, T value) { collection.AddLast(value); } protected override void ClearOnOverwriteDeserialize(ref LinkedList value) { value.Clear(); } } public sealed class QeueueFormatter : CollectionFormatterBase, Queue.Enumerator, Queue> { readonly CollectionDeserializeToBehaviour deserializeToBehaviour; public QeueueFormatter() : this(CollectionDeserializeToBehaviour.Add) { } public QeueueFormatter(CollectionDeserializeToBehaviour deserializeToBehaviour) { this.deserializeToBehaviour = deserializeToBehaviour; } protected override void Add(ref Queue collection, int index, T value) { collection.Enqueue(value); } protected override Queue Create() { return new Queue(); } protected override Queue.Enumerator GetSourceEnumerator(Queue source) { return source.GetEnumerator(); } protected override Queue Complete(ref Queue intermediateCollection) { return intermediateCollection; } protected override CollectionDeserializeToBehaviour? SupportedOverwriteBehaviour { get { return deserializeToBehaviour; } } protected override void AddOnOverwriteDeserialize(ref Queue collection, int index, T value) { collection.Enqueue(value); } protected override void ClearOnOverwriteDeserialize(ref Queue value) { value.Clear(); } } // should deserialize reverse order. public sealed class StackFormatter : CollectionFormatterBase, Stack.Enumerator, Stack> { protected override void Add(ref ArrayBuffer collection, int index, T value) { collection.Add(value); } protected override ArrayBuffer Create() { return new ArrayBuffer(4); } protected override Stack.Enumerator GetSourceEnumerator(Stack source) { return source.GetEnumerator(); } protected override Stack Complete(ref ArrayBuffer intermediateCollection) { var bufArray = intermediateCollection.Buffer; var stack = new Stack(intermediateCollection.Size); for (int i = intermediateCollection.Size - 1; i >= 0; i--) { stack.Push(bufArray[i]); } return stack; } } public sealed class HashSetFormatter : CollectionFormatterBase, HashSet.Enumerator, HashSet> { protected override void Add(ref HashSet collection, int index, T value) { collection.Add(value); } protected override HashSet Complete(ref HashSet intermediateCollection) { return intermediateCollection; } protected override HashSet Create() { return new HashSet(); } protected override HashSet.Enumerator GetSourceEnumerator(HashSet source) { return source.GetEnumerator(); } } public sealed class ReadOnlyCollectionFormatter : CollectionFormatterBase, ReadOnlyCollection> { protected override void Add(ref ArrayBuffer collection, int index, T value) { collection.Add(value); } protected override ReadOnlyCollection Complete(ref ArrayBuffer intermediateCollection) { return new ReadOnlyCollection(intermediateCollection.ToArray()); } protected override ArrayBuffer Create() { return new ArrayBuffer(4); } } public sealed class InterfaceListFormatter : CollectionFormatterBase, IList> { protected override void Add(ref List collection, int index, T value) { collection.Add(value); } protected override List Create() { return new List(); } protected override IList Complete(ref List intermediateCollection) { return intermediateCollection; } } public sealed class InterfaceCollectionFormatter : CollectionFormatterBase, ICollection> { protected override void Add(ref List collection, int index, T value) { collection.Add(value); } protected override List Create() { return new List(); } protected override ICollection Complete(ref List intermediateCollection) { return intermediateCollection; } } public sealed class InterfaceEnumerableFormatter : CollectionFormatterBase, IEnumerable> { protected override void Add(ref ArrayBuffer collection, int index, T value) { collection.Add(value); } protected override ArrayBuffer Create() { return new ArrayBuffer(4); } protected override IEnumerable Complete(ref ArrayBuffer intermediateCollection) { return intermediateCollection.ToArray(); } } // {Key:key, Elements:[Array]} (not compatible with JSON.NET) public sealed class InterfaceGroupingFormatter : IJsonFormatter> { public void Serialize(ref JsonWriter writer, IGrouping value, IJsonFormatterResolver formatterResolver) { if (value == null) { writer.WriteNull(); return; } else { writer.WriteRaw(CollectionFormatterHelper.groupingName[0]); formatterResolver.GetFormatterWithVerify().Serialize(ref writer, value.Key, formatterResolver); writer.WriteRaw(CollectionFormatterHelper.groupingName[1]); formatterResolver.GetFormatterWithVerify>().Serialize(ref writer, value.AsEnumerable(), formatterResolver); writer.WriteEndObject(); } } public IGrouping Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) { if (reader.ReadIsNull()) { return null; } else { TKey resultKey = default(TKey); IEnumerable resultValue = default(IEnumerable); reader.ReadIsBeginObjectWithVerify(); var count = 0; while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref count)) { var keyString = reader.ReadPropertyNameSegmentRaw(); int key; #if NETSTANDARD CollectionFormatterHelper.groupingAutomata.TryGetValue(keyString, out key); #else CollectionFormatterHelper.groupingAutomata.TryGetValueSafe(keyString, out key); #endif switch (key) { case 0: resultKey = formatterResolver.GetFormatterWithVerify().Deserialize(ref reader, formatterResolver); break; case 1: resultValue = formatterResolver.GetFormatterWithVerify>().Deserialize(ref reader, formatterResolver); break; default: reader.ReadNextBlock(); break; } } return new Grouping(resultKey, resultValue); } } } public sealed class InterfaceLookupFormatter : IJsonFormatter> { public void Serialize(ref JsonWriter writer, ILookup value, IJsonFormatterResolver formatterResolver) { if (value == null) { writer.WriteNull(); return; } else { formatterResolver.GetFormatterWithVerify>>().Serialize(ref writer, value.AsEnumerable(), formatterResolver); } } public ILookup Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) { if (reader.ReadIsNull()) { return null; } else { if (reader.ReadIsNull()) return null; var count = 0; var formatter = formatterResolver.GetFormatterWithVerify>(); var intermediateCollection = new Dictionary>(); reader.ReadIsBeginArrayWithVerify(); while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) { var g = formatter.Deserialize(ref reader, formatterResolver); intermediateCollection.Add(g.Key, g); } return new Lookup(intermediateCollection); } } } class Grouping : IGrouping { readonly TKey key; readonly IEnumerable elements; public Grouping(TKey key, IEnumerable elements) { this.key = key; this.elements = elements; } public TKey Key { get { return key; } } public IEnumerator GetEnumerator() { return elements.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } class Lookup : ILookup { readonly Dictionary> groupings; public Lookup(Dictionary> groupings) { this.groupings = groupings; } public IEnumerable this[TKey key] { get { return groupings[key]; } } public int Count { get { return groupings.Count; } } public bool Contains(TKey key) { return groupings.ContainsKey(key); } public IEnumerator> GetEnumerator() { return groupings.Values.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return groupings.Values.GetEnumerator(); } } // NonGenerics public sealed class NonGenericListFormatter : IJsonFormatter where T : class, IList, new() { public void Serialize(ref JsonWriter writer, T value, IJsonFormatterResolver formatterResolver) { if (value == null) { writer.WriteNull(); return; } var formatter = formatterResolver.GetFormatterWithVerify(); writer.WriteBeginArray(); if (value.Count != 0) { formatter.Serialize(ref writer, value[0], formatterResolver); } for (int i = 1; i < value.Count; i++) { writer.WriteValueSeparator(); formatter.Serialize(ref writer, value[i], formatterResolver); } writer.WriteEndArray(); } public T Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) { if (reader.ReadIsNull()) return null; var count = 0; var formatter = formatterResolver.GetFormatterWithVerify(); var list = new T(); reader.ReadIsBeginArrayWithVerify(); while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) { list.Add(formatter.Deserialize(ref reader, formatterResolver)); } return list; } } public sealed class NonGenericInterfaceEnumerableFormatter : IJsonFormatter { public static readonly IJsonFormatter Default = new NonGenericInterfaceEnumerableFormatter(); public void Serialize(ref JsonWriter writer, IEnumerable value, IJsonFormatterResolver formatterResolver) { if (value == null) { writer.WriteNull(); return; } var formatter = formatterResolver.GetFormatterWithVerify(); writer.WriteBeginArray(); var i = 0; foreach (var item in value) { if (i != 0) writer.WriteValueSeparator(); formatter.Serialize(ref writer, item, formatterResolver); } writer.WriteEndArray(); } public IEnumerable Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) { if (reader.ReadIsNull()) return null; var count = 0; var formatter = formatterResolver.GetFormatterWithVerify(); var list = new List(); reader.ReadIsBeginArrayWithVerify(); while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) { list.Add(formatter.Deserialize(ref reader, formatterResolver)); } return list; } } public sealed class NonGenericInterfaceCollectionFormatter : IJsonFormatter { public static readonly IJsonFormatter Default = new NonGenericInterfaceCollectionFormatter(); public void Serialize(ref JsonWriter writer, ICollection value, IJsonFormatterResolver formatterResolver) { if (value == null) { writer.WriteNull(); return; } var formatter = formatterResolver.GetFormatterWithVerify(); writer.WriteBeginArray(); var e = value.GetEnumerator(); try { if (e.MoveNext()) { formatter.Serialize(ref writer, e.Current, formatterResolver); while (e.MoveNext()) { writer.WriteValueSeparator(); formatter.Serialize(ref writer, e.Current, formatterResolver); } } } finally { var d = e as IDisposable; if (d != null) d.Dispose(); } writer.WriteEndArray(); } public ICollection Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) { if (reader.ReadIsNull()) return null; var count = 0; var formatter = formatterResolver.GetFormatterWithVerify(); var list = new List(); reader.ReadIsBeginArrayWithVerify(); while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) { list.Add(formatter.Deserialize(ref reader, formatterResolver)); } return list; } } public sealed class NonGenericInterfaceListFormatter : IJsonFormatter { public static readonly IJsonFormatter Default = new NonGenericInterfaceListFormatter(); public void Serialize(ref JsonWriter writer, IList value, IJsonFormatterResolver formatterResolver) { if (value == null) { writer.WriteNull(); return; } var formatter = formatterResolver.GetFormatterWithVerify(); writer.WriteBeginArray(); if (value.Count != 0) { formatter.Serialize(ref writer, value[0], formatterResolver); } for (int i = 1; i < value.Count; i++) { writer.WriteValueSeparator(); formatter.Serialize(ref writer, value[i], formatterResolver); } writer.WriteEndArray(); } public IList Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) { if (reader.ReadIsNull()) return null; var count = 0; var formatter = formatterResolver.GetFormatterWithVerify(); var list = new List(); reader.ReadIsBeginArrayWithVerify(); while (!reader.ReadIsEndArrayWithSkipValueSeparator(ref count)) { list.Add(formatter.Deserialize(ref reader, formatterResolver)); } return list; } } #if NETSTANDARD public sealed class ObservableCollectionFormatter : CollectionFormatterBase> { protected override void Add(ref ObservableCollection collection, int index, T value) { collection.Add(value); } protected override ObservableCollection Create() { return new ObservableCollection(); } } public sealed class ReadOnlyObservableCollectionFormatter : CollectionFormatterBase, ReadOnlyObservableCollection> { protected override void Add(ref ObservableCollection collection, int index, T value) { collection.Add(value); } protected override ObservableCollection Create() { return new ObservableCollection(); } protected override ReadOnlyObservableCollection Complete(ref ObservableCollection intermediateCollection) { return new ReadOnlyObservableCollection(intermediateCollection); } } public sealed class InterfaceReadOnlyListFormatter : CollectionFormatterBase, IReadOnlyList> { protected override void Add(ref ArrayBuffer collection, int index, T value) { collection.Add(value); } protected override ArrayBuffer Create() { return new ArrayBuffer(4); } protected override IReadOnlyList Complete(ref ArrayBuffer intermediateCollection) { return intermediateCollection.ToArray(); } } public sealed class InterfaceReadOnlyCollectionFormatter : CollectionFormatterBase, IReadOnlyCollection> { protected override void Add(ref ArrayBuffer collection, int index, T value) { collection.Add(value); } protected override ArrayBuffer Create() { return new ArrayBuffer(4); } protected override IReadOnlyCollection Complete(ref ArrayBuffer intermediateCollection) { return intermediateCollection.ToArray(); } } public sealed class InterfaceSetFormatter : CollectionFormatterBase, ISet> { protected override void Add(ref HashSet collection, int index, T value) { collection.Add(value); } protected override ISet Complete(ref HashSet intermediateCollection) { return intermediateCollection; } protected override HashSet Create() { return new HashSet(); } } public sealed class ConcurrentBagFormatter : CollectionFormatterBase> { protected override void Add(ref ConcurrentBag collection, int index, T value) { collection.Add(value); } protected override ConcurrentBag Create() { return new ConcurrentBag(); } } public sealed class ConcurrentQueueFormatter : CollectionFormatterBase> { protected override void Add(ref ConcurrentQueue collection, int index, T value) { collection.Enqueue(value); } protected override ConcurrentQueue Create() { return new ConcurrentQueue(); } } public sealed class ConcurrentStackFormatter : CollectionFormatterBase, ConcurrentStack> { protected override void Add(ref ArrayBuffer collection, int index, T value) { collection.Add(value); } protected override ArrayBuffer Create() { return new ArrayBuffer(4); } protected override ConcurrentStack Complete(ref ArrayBuffer intermediateCollection) { var bufArray = intermediateCollection.Buffer; var stack = new ConcurrentStack(); for (int i = intermediateCollection.Size - 1; i >= 0; i--) { stack.Push(bufArray[i]); } return stack; } } #endif } namespace Utf8Json.Formatters.Internal { internal static class CollectionFormatterHelper { internal static readonly byte[][] groupingName; internal static readonly AutomataDictionary groupingAutomata; static CollectionFormatterHelper() { groupingName = new byte[][] { JsonWriter.GetEncodedPropertyNameWithBeginObject("Key"), JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Elements"), }; groupingAutomata = new AutomataDictionary { {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Key"), 0 }, {JsonWriter.GetEncodedPropertyNameWithoutQuotation("Elements"), 1 }, }; } } }