using System; using System.Collections.Generic; using System.Collections.ObjectModel; #if NETSTANDARD using System.Collections.Concurrent; #endif namespace Utf8Json.Formatters { // unfortunately, can't use IDictionary because supports IReadOnlyDictionary. public abstract class DictionaryFormatterBase : IJsonFormatter where TDictionary : class, IEnumerable> where TEnumerator : IEnumerator> { public void Serialize(ref JsonWriter writer, TDictionary value, IJsonFormatterResolver formatterResolver) { if (value == null) { writer.WriteNull(); return; } else { var keyFormatter = formatterResolver.GetFormatterWithVerify() as IObjectPropertyNameFormatter; var valueFormatter = formatterResolver.GetFormatterWithVerify(); writer.WriteBeginObject(); var e = GetSourceEnumerator(value); try { if (keyFormatter != null) { if (e.MoveNext()) { var item = e.Current; keyFormatter.SerializeToPropertyName(ref writer, item.Key, formatterResolver); writer.WriteNameSeparator(); valueFormatter.Serialize(ref writer, item.Value, formatterResolver); } else { goto END; } while (e.MoveNext()) { writer.WriteValueSeparator(); var item = e.Current; keyFormatter.SerializeToPropertyName(ref writer, item.Key, formatterResolver); writer.WriteNameSeparator(); valueFormatter.Serialize(ref writer, item.Value, formatterResolver); } } else { if (e.MoveNext()) { var item = e.Current; writer.WriteString(item.Key.ToString()); writer.WriteNameSeparator(); valueFormatter.Serialize(ref writer, item.Value, formatterResolver); } else { goto END; } while (e.MoveNext()) { writer.WriteValueSeparator(); var item = e.Current; writer.WriteString(item.Key.ToString()); writer.WriteNameSeparator(); valueFormatter.Serialize(ref writer, item.Value, formatterResolver); } } } finally { e.Dispose(); } END: writer.WriteEndObject(); } } public TDictionary Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) { if (reader.ReadIsNull()) { return null; } else { var keyFormatter = formatterResolver.GetFormatterWithVerify() as IObjectPropertyNameFormatter; if (keyFormatter == null) throw new InvalidOperationException(typeof(TKey) + " does not support dictionary key deserialize."); var valueFormatter = formatterResolver.GetFormatterWithVerify(); reader.ReadIsBeginObjectWithVerify(); var dict = Create(); var i = 0; while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref i)) { var key = keyFormatter.DeserializeFromPropertyName(ref reader, formatterResolver); reader.ReadIsNameSeparatorWithVerify(); var value = valueFormatter.Deserialize(ref reader, formatterResolver); Add(ref dict, i - 1, key, value); } return Complete(ref dict); } } // abstraction for serialize // Some collections can use struct iterator, this is optimization path protected abstract TEnumerator GetSourceEnumerator(TDictionary source); // abstraction for deserialize protected abstract TIntermediate Create(); protected abstract void Add(ref TIntermediate collection, int index, TKey key, TValue value); protected abstract TDictionary Complete(ref TIntermediate intermediateCollection); } public abstract class DictionaryFormatterBase : DictionaryFormatterBase>, TDictionary> where TDictionary : class, IEnumerable> { protected override IEnumerator> GetSourceEnumerator(TDictionary source) { return source.GetEnumerator(); } } public abstract class DictionaryFormatterBase : DictionaryFormatterBase where TDictionary : class, IDictionary { protected override TDictionary Complete(ref TDictionary intermediateCollection) { return intermediateCollection; } } public sealed class DictionaryFormatter : DictionaryFormatterBase, Dictionary.Enumerator, Dictionary> { protected override void Add(ref Dictionary collection, int index, TKey key, TValue value) { collection.Add(key, value); } protected override Dictionary Complete(ref Dictionary intermediateCollection) { return intermediateCollection; } protected override Dictionary Create() { return new Dictionary(); } protected override Dictionary.Enumerator GetSourceEnumerator(Dictionary source) { return source.GetEnumerator(); } } public sealed class GenericDictionaryFormatter : DictionaryFormatterBase where TDictionary : class, IDictionary, new() { protected override void Add(ref TDictionary collection, int index, TKey key, TValue value) { collection.Add(key, value); } protected override TDictionary Create() { return new TDictionary(); } } public sealed class InterfaceDictionaryFormatter : DictionaryFormatterBase, IDictionary> { protected override void Add(ref Dictionary collection, int index, TKey key, TValue value) { collection.Add(key, value); } protected override Dictionary Create() { return new Dictionary(); } protected override IDictionary Complete(ref Dictionary intermediateCollection) { return intermediateCollection; } } public sealed class SortedListFormatter : DictionaryFormatterBase> { protected override void Add(ref SortedList collection, int index, TKey key, TValue value) { collection.Add(key, value); } protected override SortedList Create() { return new SortedList(); } } public sealed class SortedDictionaryFormatter : DictionaryFormatterBase, SortedDictionary.Enumerator, SortedDictionary> { protected override void Add(ref SortedDictionary collection, int index, TKey key, TValue value) { collection.Add(key, value); } protected override SortedDictionary Complete(ref SortedDictionary intermediateCollection) { return intermediateCollection; } protected override SortedDictionary Create() { return new SortedDictionary(); } protected override SortedDictionary.Enumerator GetSourceEnumerator(SortedDictionary source) { return source.GetEnumerator(); } } #if NETSTANDARD public sealed class ReadOnlyDictionaryFormatter : DictionaryFormatterBase, ReadOnlyDictionary> { protected override void Add(ref Dictionary collection, int index, TKey key, TValue value) { collection.Add(key, value); } protected override ReadOnlyDictionary Complete(ref Dictionary intermediateCollection) { return new ReadOnlyDictionary(intermediateCollection); } protected override Dictionary Create() { return new Dictionary(); } } public sealed class InterfaceReadOnlyDictionaryFormatter : DictionaryFormatterBase, IReadOnlyDictionary> { protected override void Add(ref Dictionary collection, int index, TKey key, TValue value) { collection.Add(key, value); } protected override IReadOnlyDictionary Complete(ref Dictionary intermediateCollection) { return intermediateCollection; } protected override Dictionary Create() { return new Dictionary(); } } public sealed class ConcurrentDictionaryFormatter : DictionaryFormatterBase> { protected override void Add(ref ConcurrentDictionary collection, int index, TKey key, TValue value) { collection.TryAdd(key, value); } protected override ConcurrentDictionary Create() { // concurrent dictionary can't access defaultConcurrecyLevel so does not use count overload. return new ConcurrentDictionary(); } } #endif public sealed class NonGenericDictionaryFormatter : IJsonFormatter where T : class, System.Collections.IDictionary, new() { public void Serialize(ref JsonWriter writer, T value, IJsonFormatterResolver formatterResolver) { if (value == null) { writer.WriteNull(); return; } else { var valueFormatter = formatterResolver.GetFormatterWithVerify(); writer.WriteBeginObject(); var e = value.GetEnumerator(); try { if (e.MoveNext()) { System.Collections.DictionaryEntry item = (System.Collections.DictionaryEntry)e.Current; writer.WritePropertyName(item.Key.ToString()); valueFormatter.Serialize(ref writer, item.Value, formatterResolver); } else { goto END; } while (e.MoveNext()) { writer.WriteValueSeparator(); System.Collections.DictionaryEntry item = (System.Collections.DictionaryEntry)e.Current; writer.WritePropertyName(item.Key.ToString()); valueFormatter.Serialize(ref writer, item.Value, formatterResolver); } } finally { var disp = e as IDisposable; if (disp != null) { disp.Dispose(); } } END: writer.WriteEndObject(); } } public T Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) { if (reader.ReadIsNull()) { return default(T); } else { var valueFormatter = formatterResolver.GetFormatterWithVerify(); reader.ReadIsBeginObjectWithVerify(); var dict = new T(); var i = 0; while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref i)) { var key = reader.ReadPropertyName(); var value = valueFormatter.Deserialize(ref reader, formatterResolver); dict.Add(key, value); } return dict; } } } public sealed class NonGenericInterfaceDictionaryFormatter : IJsonFormatter { public static readonly IJsonFormatter Default = new NonGenericInterfaceDictionaryFormatter(); public void Serialize(ref JsonWriter writer, System.Collections.IDictionary value, IJsonFormatterResolver formatterResolver) { if (value == null) { writer.WriteNull(); return; } else { var valueFormatter = formatterResolver.GetFormatterWithVerify(); writer.WriteBeginObject(); var e = value.GetEnumerator(); try { if (e.MoveNext()) { System.Collections.DictionaryEntry item = (System.Collections.DictionaryEntry)e.Current; writer.WritePropertyName(item.Key.ToString()); valueFormatter.Serialize(ref writer, item.Value, formatterResolver); } else { goto END; } while (e.MoveNext()) { writer.WriteValueSeparator(); System.Collections.DictionaryEntry item = (System.Collections.DictionaryEntry)e.Current; writer.WritePropertyName(item.Key.ToString()); valueFormatter.Serialize(ref writer, item.Value, formatterResolver); } } finally { var disp = e as IDisposable; if (disp != null) { disp.Dispose(); } } END: writer.WriteEndObject(); } } public System.Collections.IDictionary Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver) { if (reader.ReadIsNull()) { return null; } else { var valueFormatter = formatterResolver.GetFormatterWithVerify(); reader.ReadIsBeginObjectWithVerify(); var dict = new Dictionary(); var i = 0; while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref i)) { var key = reader.ReadPropertyName(); var value = valueFormatter.Deserialize(ref reader, formatterResolver); dict.Add(key, value); } return dict; } } } }